[其他ST产品] STM32 HAL 硬件IIC+DMA+简单图形库控制OLED

[复制链接]
4315|45
 楼主| wangtaohui 发表于 2023-6-28 20:14 | 显示全部楼层 |阅读模式
前言

本文将介绍在STM32 HAL库下实现硬件IIC+DMA控制0.96寸 OLED屏,以及OLED图形库的移植。


9620649c23f595739.png


一、建立工程

平台:野火指南者STM32F103VET6 + STM32Cube MX + Keil MDK 5

(示例)
1.选择所用MCU。

31716649c240832a44.png

 楼主| wangtaohui 发表于 2023-6-28 20:14 | 显示全部楼层
2.选择启用晶振 84408649c241971560.png
 楼主| wangtaohui 发表于 2023-6-28 20:14 | 显示全部楼层
3.选择Debug方式

59409649c2428bc316.png
 楼主| wangtaohui 发表于 2023-6-28 20:14 | 显示全部楼层
4.设置时钟树

57489649c243e9c2e5.png
 楼主| wangtaohui 发表于 2023-6-28 20:15 | 显示全部楼层
5.选择合适的引脚开启I2C

49576649c244caedbd.png
 楼主| wangtaohui 发表于 2023-6-28 20:15 | 显示全部楼层
6.加入I2Cx_TX的DMA
43666649c245c673d5.png
 楼主| wangtaohui 发表于 2023-6-28 20:15 | 显示全部楼层
7.开启12Cx_event_interrupt
17834649c246b233db.png
 楼主| wangtaohui 发表于 2023-6-28 20:15 | 显示全部楼层
8.配置完后建立工程
6491649c247975826.png
 楼主| wangtaohui 发表于 2023-6-28 20:16 | 显示全部楼层
二、编写和移植
本节主要介绍移植标准库编写的oledlib图形库过程。
oledlib库原作者:MjGame
原作例程开源地址:MjGame 的例程
本文使用的oledlib库修订者:一只程序缘
本文所要移植库的开源地址:一只程序缘 的例程

git clone https://gitee.com/jiezhuonew/oledlib.git
————————————————
版权声明:本文为CSDN博主「乙酸氧铍」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44457994/article/details/114768659
 楼主| wangtaohui 发表于 2023-6-28 20:17 | 显示全部楼层
前期准备
1.先导入所需的文件
所用Delay文件参考《无需另配定时器在STM32 HAL下实现微秒级延时(兼容FreeRTOS)》

72356649c24bc6f3f2.png

38974649c24c295f58.png
 楼主| wangtaohui 发表于 2023-6-28 20:17 | 显示全部楼层
2.将delay.h改为我们所用的Delay.h文件
99686649c24cf2063d.png
24833649c24d53fd86.png
 楼主| wangtaohui 发表于 2023-6-28 20:17 | 显示全部楼层
修改u16为unsigned short或uint16_t
3502649c24e20e162.png
26962649c24ee4df87.png
 楼主| wangtaohui 发表于 2023-6-28 20:19 | 显示全部楼层
驱动部分修改
在oled_config.h中添加#include “main.h”,并修改TRANSFER_METHOD

9925649c256c19bc8.png
 楼主| wangtaohui 发表于 2023-6-28 20:20 | 显示全部楼层
在oled_driver.h和oled_driver.c中注释掉标准库相关的东西:
65822649c257861c1e.png
95996649c257fe7b5d.png
 楼主| wangtaohui 发表于 2023-6-28 20:20 | 显示全部楼层
此时编译不再弹出错误。
60970649c258f22296.png
 楼主| wangtaohui 发表于 2023-6-28 20:20 | 显示全部楼层
在oled_driver.c修改I2C_WriteByte函数
  1.         /**
  2.                  [url=home.php?mod=space&uid=247401]@brief[/url]  I2C_WriteByte,向OLED寄存器地址写一个byte的数据
  3.                  @param  addr:寄存器地址
  4.                                                  data:要写入的数据
  5.                  @retval 无
  6.         */
  7.         void I2C_WriteByte(uint8_t addr, uint8_t data)
  8.         {
  9. //                while (I2C_GetFlagStatus(I2CX, I2C_FLAG_BUSY));

  10. //                I2C_GenerateSTART(I2CX, ENABLE);//开启I2C1
  11. //                while (!I2C_CheckEvent(I2CX, I2C_EVENT_MASTER_MODE_SELECT)); /*EV5,主模式*/

  12. //                I2C_Send7bitAddress(I2CX, OLED_ADDRESS, I2C_Direction_Transmitter);//器件地址 -- 默认0x78
  13. //                while (!I2C_CheckEvent(I2CX, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  14. //                I2C_SendData(I2CX, addr);//寄存器地址
  15. //                while (!I2C_CheckEvent(I2CX, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  16. //                I2C_SendData(I2CX, data);//发送数据
  17. //                while (!I2C_CheckEvent(I2CX, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  18. //                I2C_GenerateSTOP(I2CX, ENABLE);//关闭I2C1总线
  19.                 extern I2C_HandleTypeDef hi2c1;
  20.                 HAL_I2C_Mem_Write(&hi2c1, OLED_ADDRESS, addr, I2C_MEMADD_SIZE_8BIT, &data, 1, 10);
  21.         }
 楼主| wangtaohui 发表于 2023-6-28 20:21 | 显示全部楼层
在oled_driver.c修改OLED_CLS函数
  1. void OLED_CLS(void)//清屏
  2. {
  3. //        unsigned char m, n;
  4. //        for (m = 0; m < 8; m++)
  5. //        {
  6. //                WriteCmd(0xb0 + m); //page0-page1
  7. //                WriteCmd(0x00);   //low column start address
  8. //                WriteCmd(0x10);   //high column start address
  9. //                for (n = 0; n < 128; n++)
  10. //                {
  11. //                        WriteDat(0x00);
  12. //                }
  13. //        }

  14.         extern unsigned char ScreenBuffer[SCREEN_PAGE_NUM][SCREEN_COLUMN];

  15.     uint16_t i;
  16.     for (i = 0; i < SCREEN_PAGE_NUM * SCREEN_COLUMN; ++i)
  17.     {
  18.         ScreenBuffer[0][i] = 0;
  19.     }
  20.         OLED_FILL(ScreenBuffer[0]);
  21. }
 楼主| wangtaohui 发表于 2023-6-28 20:21 | 显示全部楼层
在oled_driver.c修改OLED_FILL函数
  1. void OLED_FILL(unsigned char BMP[])
  2. {
  3. //        uint8_t i, j;
  4.         unsigned char *p;
  5.         p = BMP;

  6. //        for (i = 0; i < 8; i++)
  7. //        {
  8. //                WriteCmd(0xb0 + i); //page0-page1
  9. //                WriteCmd(0x00);   //low column start address
  10. //                WriteCmd(0x10);

  11. //                for (j = 0; j < 128; j++)
  12. //                {
  13. //                        WriteDat(*p++);
  14. //                }
  15. //        }
  16.         extern I2C_HandleTypeDef hi2c1;
  17.     while(hi2c1.State != HAL_I2C_STATE_READY);
  18.     HAL_I2C_Mem_Write_DMA(&hi2c1, OLED_ADDRESS, 0x40, I2C_MEMADD_SIZE_8BIT, p, SCREEN_PAGE_NUM * SCREEN_PAGEDATA_NUM);
  19. }
 楼主| wangtaohui 发表于 2023-6-28 20:22 | 显示全部楼层
注意到
  1. //请将此函数放入1ms中断里,为图形提供时基
  2. //系统时间基准主要用于FrameRateUpdateScreen()中固定帧率刷新屏幕
  3. void OledTimeMsFunc(void)
  4. {
  5.         if(OledTimeMs != 0x00)
  6.         {
  7.                 OledTimeMs--;
  8.         }
  9. }
 楼主| wangtaohui 发表于 2023-6-28 20:22 | 显示全部楼层
故到stm32f1xx_it.c中声明并添加此函数
若未使用FreeRTOS则在滴答定时器中断中添加,反之在对应定时器中断中添加:
  1. /**
  2.   * @brief This function handles System tick timer.
  3.   */
  4. void SysTick_Handler(void)
  5. {
  6.   /* USER CODE BEGIN SysTick_IRQn 0 */

  7.   /* USER CODE END SysTick_IRQn 0 */
  8.   HAL_IncTick();
  9.   /* USER CODE BEGIN SysTick_IRQn 1 */
  10.   OledTimeMsFunc();
  11.   /* USER CODE END SysTick_IRQn 1 */
  12. }
您需要登录后才可以回帖 登录 | 注册

本版积分规则

43

主题

529

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部