[活动专区] 【AT-START-L021测评】0.96寸OLED驱动

[复制链接]
 楼主| 2218120025 发表于 2025-1-4 22:31 | 显示全部楼层 |阅读模式
       OLED是常见的显示模块,本次是用雅特力AT-START-L021来驱动主控芯片为SSD1306的0.96寸OLED模块,使用的是IIC进行通信。
       首先是在新创建的工程中添加i2c_application.c(在BSP文件夹下)和at32l021_i2c.c和at32l021_dma.c(在FIRMWARE文件夹下)。其中at32l021_dma.c在i2c_application.c中引用,但是实际的工程中没有使用到,去掉编译会有问题。
       其次是在main函数中调用IIC初始化相关函数,这里参考了IIC例程。在main.c中添加如下的IIC对应的GPIO口初始化函数
  1. void i2c_lowlevel_init(i2c_handle_type* hi2c)
  2. {
  3.   gpio_init_type gpio_init_structure;

  4.   if(hi2c->i2cx == I2Cx_PORT)
  5.   {
  6.     /* i2c periph clock enable */
  7.     crm_periph_clock_enable(I2Cx_CLK, TRUE);
  8.     crm_periph_clock_enable(I2Cx_SCL_GPIO_CLK, TRUE);
  9.     crm_periph_clock_enable(I2Cx_SDA_GPIO_CLK, TRUE);

  10.     /* gpio configuration */
  11.     gpio_pin_mux_config(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_GPIO_PinsSource, I2Cx_SCL_GPIO_MUX);

  12.     gpio_pin_mux_config(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_GPIO_PinsSource, I2Cx_SDA_GPIO_MUX);

  13.     /* configure i2c pins: scl */
  14.     gpio_init_structure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
  15.     gpio_init_structure.gpio_mode           = GPIO_MODE_MUX;
  16.     gpio_init_structure.gpio_out_type       = GPIO_OUTPUT_OPEN_DRAIN;
  17.     gpio_init_structure.gpio_pull           = GPIO_PULL_NONE;

  18.     gpio_init_structure.gpio_pins           = I2Cx_SCL_GPIO_PIN;
  19.     gpio_init(I2Cx_SCL_GPIO_PORT, &gpio_init_structure);

  20.     /* configure i2c pins: sda */
  21.     gpio_init_structure.gpio_pins           = I2Cx_SDA_GPIO_PIN;
  22.     gpio_init(I2Cx_SDA_GPIO_PORT, &gpio_init_structure);

  23.     /* config i2c */
  24.     i2c_init(hi2c->i2cx, 0x0F, I2Cx_CLKCTRL);

  25.     i2c_own_address1_set(hi2c->i2cx, I2C_ADDRESS_MODE_7BIT, I2Cx_ADDRESS);
  26.   }
  27. }
      在main中添加如下的宏定义
  1. #define I2C_TIMEOUT                      0xFFFFFFF

  2. //#define I2Cx_CLKCTRL                   0xF070F7F7   //10K
  3. //#define I2Cx_CLKCTRL                   0x60F06C6C   //50K
  4. #define I2Cx_CLKCTRL                     0x60F03333   //100K
  5. //#define I2Cx_CLKCTRL                   0x20C02C4F   //200K

  6. //#define I2Cx_ADDRESS                     0xA0

  7. #define I2Cx_PORT                        I2C1
  8. #define I2Cx_CLK                         CRM_I2C1_PERIPH_CLOCK
  9. #define I2Cx_DMA                         DMA1
  10. #define I2Cx_DMA_CLK                     CRM_DMA1_PERIPH_CLOCK

  11. #define I2Cx_SCL_GPIO_CLK                CRM_GPIOB_PERIPH_CLOCK
  12. #define I2Cx_SCL_GPIO_PIN                GPIO_PINS_6
  13. #define I2Cx_SCL_GPIO_PinsSource         GPIO_PINS_SOURCE6
  14. #define I2Cx_SCL_GPIO_PORT               GPIOB
  15. #define I2Cx_SCL_GPIO_MUX                GPIO_MUX_1

  16. #define I2Cx_SDA_GPIO_CLK                CRM_GPIOB_PERIPH_CLOCK
  17. #define I2Cx_SDA_GPIO_PIN                GPIO_PINS_7
  18. #define I2Cx_SDA_GPIO_PinsSource         GPIO_PINS_SOURCE7
  19. #define I2Cx_SDA_GPIO_PORT               GPIOB
  20. #define I2Cx_SDA_GPIO_MUX                GPIO_MUX_1
       在main中添加对应的.h调用代码
  1. #include "i2c_application.h"
       main函数中调用IIC初始化的代码如下
  1. hi2cx.i2cx = I2Cx_PORT;

  2.   /* i2c config */
  3.   i2c_config(&hi2cx);

        之后是添加OLED的驱动,这里是参考常用的OLED驱动,只是修改发送数据的代码,OLED.c的代码如下
  1. #include "oled.h"
  2. #include "oledfont.h"
  3. #include "i2c_application.h"

  4. i2c_handle_type OLEDhi2cx;

  5. void OLED_WriteByte(uint8_t data, uint8_t mode);
  6. void OLED_Clear(void);
  7. void OLED_SetPos(uint8_t x, uint8_t y);
  8. void OLED_DrawBMP(uint8_t x, uint8_t y, uint8_t sizex, uint8_t sizey, const uint8_t BMP[]);
  9. /*
  10. 函 数 名:OLED_WriteByte
  11. 功    能:发送一个字节
  12. 参数描述:data:发送数据
  13.          mode:模式选择   0:命令   1:数据
  14. 返 回 值:无
  15. */
  16. void OLED_WriteByte(uint8_t data, uint8_t mode)
  17. {
  18.     uint8_t u8Senddata[2] = {0};
  19.     u8Senddata[0] = mode;
  20.     u8Senddata[1] = data;
  21.     i2c_master_transmit(&OLEDhi2cx,OLED_ADDR, u8Senddata, 2, 0xFF);
  22. }

  23. /*
  24. 函 数 名:OLED_Clear
  25. 功    能:清屏
  26. 参数描述:无
  27. 返 回 值:无
  28. */
  29. void OLED_Clear(void)  
  30. {  
  31.     uint8_t i,n;      
  32.     for(i=0; i<OLED_PAGE_SUM; i++)  
  33.     {  
  34.         OLED_WriteByte (OLED_REG_PAGE_SET + i,OLED_SEND_CMD);    /* 设置页地址(0~7) */
  35.         OLED_WriteByte (OLED_REG_LINE_L_SET,OLED_SEND_CMD);      /* 设置显示位置—列低地址 */
  36.         OLED_WriteByte (OLED_REG_LINE_H_SET,OLED_SEND_CMD);      /* 设置显示位置—列高地址 */   
  37.         for(n=0; n<128; n++)
  38.         {
  39.             OLED_WriteByte(0,OLED_SEND_DATA);
  40.         }//更新显示
  41.     }
  42. }

  43. /*
  44. 函 数 名:OLED_SetPos
  45. 功    能:坐标设置
  46. 参数描述:x:横坐标
  47.          Y:纵坐标
  48. 返 回 值:无
  49. */
  50. void OLED_SetPos(uint8_t x, uint8_t y)
  51. {
  52.   OLED_WriteByte(0xb0 + y, OLED_SEND_CMD);
  53.   OLED_WriteByte(((x & 0xf0) >> 4) | 0x10, OLED_SEND_CMD);
  54.   OLED_WriteByte((x & 0x0f), OLED_SEND_CMD);
  55. }   

  56. /*
  57. 函 数 名:OLED_DrawBMP
  58. 功    能:显示图片
  59. 参数描述:x, y:起始坐标
  60.         sizex, sizey:终止坐标
  61.         BMP:图像数据
  62. 返 回 值:无
  63. */
  64. void OLED_DrawBMP(uint8_t x, uint8_t y, uint8_t sizex, uint8_t sizey, const uint8_t BMP[])
  65. {   
  66.   uint16_t j=0;
  67.   uint8_t i, m, temp;
  68.   sizey = sizey / 8 + ((sizey % 8) ? 1 : 0);
  69.   for(i = 0; i < sizey; i++)
  70.   {
  71.     OLED_SetPos(x, i + y);
  72.     for(m = 0; m < sizex; m++)
  73.     {
  74.        temp = BMP[j++];
  75.        OLED_WriteByte(temp, OLED_SEND_DATA);
  76.     }
  77.   }
  78. }
  79. //屏幕旋转180度
  80. void OLED_DisplayTurn(uint8_t i)
  81. {
  82.   if(i==0)
  83.     {
  84.       OLED_WriteByte(0xC8,OLED_SEND_CMD);//正常显示
  85.       OLED_WriteByte(0xA1,OLED_SEND_CMD);
  86.     }
  87. else
  88.     {
  89.       OLED_WriteByte(0xC0,OLED_SEND_CMD);//反转显示
  90.       OLED_WriteByte(0xA0,OLED_SEND_CMD);
  91.     }
  92. }
  93. /*
  94. 函 数 名:OLED_Init
  95. 功    能:OLED初始化
  96. 参数描述:无
  97. 返 回 值:无
  98. */
  99. void OLED_Init()
  100. {
  101.     OLEDhi2cx.i2cx = I2C1;
  102.     OLED_WriteByte(0xAE,OLED_SEND_CMD);//--turn off oled panel
  103.     OLED_WriteByte(0x00,OLED_SEND_CMD);//---set low column address
  104.     OLED_WriteByte(0x10,OLED_SEND_CMD);//---set high column address
  105.     OLED_WriteByte(0x40,OLED_SEND_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
  106.     OLED_WriteByte(0x81,OLED_SEND_CMD);//--set contrast control register
  107.     OLED_WriteByte(0xCF,OLED_SEND_CMD); // Set SEG Output Current Brightness
  108.     OLED_WriteByte(0xA1,OLED_SEND_CMD);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
  109.     OLED_WriteByte(0xC8,OLED_SEND_CMD);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
  110.     OLED_WriteByte(0xA6,OLED_SEND_CMD);//--set normal display
  111.     OLED_WriteByte(0xA8,OLED_SEND_CMD);//--set multiplex ratio(1 to 64)
  112.     OLED_WriteByte(0x3f,OLED_SEND_CMD);//--1/64 duty
  113.     OLED_WriteByte(0xD3,OLED_SEND_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
  114.     OLED_WriteByte(0x00,OLED_SEND_CMD);//-not offset
  115.     OLED_WriteByte(0xd5,OLED_SEND_CMD);//--set display clock divide ratio/oscillator frequency
  116.     OLED_WriteByte(0x80,OLED_SEND_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
  117.     OLED_WriteByte(0xD9,OLED_SEND_CMD);//--set pre-charge period
  118.     OLED_WriteByte(0xF1,OLED_SEND_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
  119.     OLED_WriteByte(0xDA,OLED_SEND_CMD);//--set com pins hardware configuration
  120.     OLED_WriteByte(0x12,OLED_SEND_CMD);
  121.     OLED_WriteByte(0xDB,OLED_SEND_CMD);//--set vcomh
  122.     OLED_WriteByte(0x40,OLED_SEND_CMD);//Set VCOM Deselect Level
  123.     OLED_WriteByte(0x20,OLED_SEND_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
  124.     OLED_WriteByte(0x02,OLED_SEND_CMD);//
  125.     OLED_WriteByte(0x8D,OLED_SEND_CMD);//--set Charge Pump enable/disable
  126.     OLED_WriteByte(0x14,OLED_SEND_CMD);//--set(0x10) disable
  127.     OLED_WriteByte(0xA4,OLED_SEND_CMD);// Disable Entire Display On (0xa4/0xa5)
  128.     OLED_WriteByte(0xA6,OLED_SEND_CMD);// Disable Inverse Display On (0xa6/a7)
  129.     OLED_Clear();
  130.     OLED_WriteByte(0xAF,OLED_SEND_CMD); /*display ON*/
  131.     OLED_DisplayTurn(1);//0正常显示 1翻转180度显示
  132. }

  133. /*
  134. 函 数 名:OLED_Init
  135. 功    能:OLED初始化
  136. 参数描述:无
  137. 返 回 值:无
  138. */
  139. void OLED_Test(void)
  140. {
  141.     OLED_DrawBMP(0, 0, 128, 64, BMP1);
  142. }


  143. //在指定位置显示一个字符
  144. //x:0~127
  145. //y:0~63         
  146. //sizey:选择字体 6x8  8x16
  147. void OLED_ShowChar(uint8_t x, uint8_t y,const uint8_t chr, uint8_t sizey)
  148. {      
  149.     uint8_t c = 0, sizex = sizey / 2, temp;
  150.     uint16_t i = 0, size1;
  151.     if (sizey == 8)
  152.     {
  153.         size1=6;
  154.     }
  155.     else
  156.     {
  157.         size1=(sizey/8+((sizey%8)?1:0))*(sizey/2);
  158.     }
  159.     c = chr - ' ';//得到偏移后的值
  160.    
  161.     OLED_SetPos(x,y);
  162.     for(i = 0; i < size1; i++)
  163.     {
  164.         if(((i % sizex) == 0) && (sizey != 8))
  165.         {
  166.             OLED_SetPos(x,y++);
  167.         }
  168.         if( sizey == 8)
  169.         {
  170.             temp = asc2_0806[c][i];
  171.             OLED_WriteByte(temp,OLED_SEND_DATA);//6X8字号
  172.         }
  173.         else if(sizey == 16)
  174.         {
  175.             temp=asc2_1608[c][i];
  176.             OLED_WriteByte(temp,OLED_SEND_DATA);//8x16字号
  177.         }
  178.         else
  179.         {
  180.             return;
  181.         }
  182.   }
  183. }
  184. //显示一个字符号串
  185. void OLED_ShowString(uint8_t x, uint8_t y,const char *chr, uint8_t sizey)
  186. {
  187.   uint8_t j = 0;
  188.   while (chr[j] != '\0')
  189.   {   
  190.     OLED_ShowChar(x, y, chr[j++], sizey);
  191.     if(sizey == 8)
  192.     {
  193.         x+=6;
  194.     }
  195.     else
  196.     {
  197.         x += (sizey / 2);
  198.     }
  199.   }
  200. }
  201. //m^n函数
  202. uint32_t oled_pow(uint8_t m,uint8_t n)
  203. {
  204.   uint32_t result=1;  
  205.   while(n--)result*=m;   
  206.   return result;
  207. }
  208. //显示数字
  209. //x,y :起点坐标
  210. //num:要显示的数字
  211. //len :数字的位数
  212. //sizey:字体大小      
  213. void OLED_ShowNum(unsigned char x,unsigned char y,unsigned int num,unsigned char len,unsigned char sizey)
  214. {           
  215.   uint8_t t,temp,m=0;
  216.   uint8_t enshow=0;
  217.   if(sizey==8)m=2;
  218.   for(t=0;t<len;t++)
  219.   {
  220.     temp=(num/oled_pow(10,len-t-1))%10;
  221.     if(enshow==0&&t<(len-1))
  222.     {
  223.       if(temp==0)
  224.       {
  225.         OLED_ShowChar(x+(sizey/2+m)*t,y,' ',sizey);
  226.         continue;
  227.       }else enshow=1;
  228.     }
  229.     OLED_ShowChar(x+(sizey/2+m)*t,y,temp+'0',sizey);
  230.   }
  231. }


       其中在OLED.c中定义了对应的IIC句柄
  1. i2c_handle_type OLEDhi2cx;
       在OLED_Init函数中添加了句柄的赋值
  1. OLEDhi2cx.i2cx = I2C1;
       主要是和main函数中初始化的IIC是一个IIC外设。
        OLED发送函数使用i2c_application.c中的i2c_master_transmit函数,发送函数定义如下
  1. void OLED_WriteByte(uint8_t data, uint8_t mode)
  2. {
  3.     uint8_t u8Senddata[2] = {0};
  4.     u8Senddata[0] = mode;
  5.     u8Senddata[1] = data;
  6.     i2c_master_transmit(&OLEDhi2cx,OLED_ADDR, u8Senddata, 2, 0xFF);
  7. }
      引脚连接图如下
7337367794623021b1.png

       实现效果如下
IMG_20250104_222245.jpg

        工程文件: OLEDProject.zip (2.16 MB, 下载次数: 7)
呐咯密密 发表于 2025-1-7 15:23 | 显示全部楼层
这是使用的图片显示吗
 楼主| 2218120025 发表于 2025-1-8 09:06 | 显示全部楼层
呐咯密密 发表于 2025-1-7 15:23
这是使用的图片显示吗

代码   用专门的工具把图片转换成显示的点的数组
WhisperingTrees 发表于 2025-1-21 09:39 | 显示全部楼层
我在用这种屏幕的时候经常会遇到部分位置乱码,特别是在不断更新的数据显示的时候。
elsaflower 发表于 2025-2-4 18:03 | 显示全部楼层
0.96 寸 OLED 模块体积小巧。两者搭配能在有限的电路板空间内实现显示功能,对于小型化、便携式设备的开发十分有利
backlugin 发表于 2025-2-4 20:19 | 显示全部楼层
SSD1306 作为常见的 OLED 主控芯片,已有丰富的开源驱动代码和资料可供参考。
burgessmaggie 发表于 2025-2-4 20:53 | 显示全部楼层
在新创建的工程中添加相关的I2C驱动文件和OLED驱动文件。这些文件包含了I2C初始化、OLED初始化、数据显示等函数,为实现OLED驱动提供了必要的软件支持。
vivilyly 发表于 2025-2-5 07:39 | 显示全部楼层
该芯片具有ARM Cortex®-M0+内核,实现了高性能与低功耗的完美结合。
juliestephen 发表于 2025-2-5 09:43 | 显示全部楼层
有完善的错误处理机制              
caigang13 发表于 2025-2-5 10:09 来自手机 | 显示全部楼层
这个0.96寸的OLED屏出镜率很高啊。
zerorobert 发表于 2025-2-5 10:14 | 显示全部楼层
要确保上拉电阻的阻值合适(通常为4.7kΩ左右),以保证IIC信号的正常传输。
ulystronglll 发表于 2025-2-5 14:48 | 显示全部楼层
0.96寸的OLED屏幕尺寸有限,显示的信息量相对较少
minzisc 发表于 2025-2-5 15:46 | 显示全部楼层
虽然IIC通信速度相对较慢,但可以在一定范围内进行优化。
mickit 发表于 2025-2-5 17:09 | 显示全部楼层
在干扰环境下,IIC通信是否可靠,是否有错误检测和重试机制。
maudlu 发表于 2025-2-5 18:01 | 显示全部楼层
便于扩展OLED的功能。              
olivem55arlowe 发表于 2025-2-5 18:48 | 显示全部楼层
IIC 通信速率相对有限,在需要高速刷新屏幕内容或传输大量数据时,可能无法满足需求,导致显示出现延迟或卡顿现象。
youtome 发表于 2025-2-5 20:45 | 显示全部楼层
IIC总线是一种常用的双向二线制串行总线,适用于连接低速的外围设备,如OLED显示器。它简化了硬件接口,降低了设计复杂性。
youtome 发表于 2025-2-5 22:27 | 显示全部楼层
该设计充分利用了雅特力AT-START-L021开发板的高性能和丰富外设资源,通过IIC总线实现了对SSD1306主控芯片的OLED模块的驱动。
chenci2013 发表于 2025-2-5 22:55 | 显示全部楼层
OLED模块的显示效果非常出色,对比度高,色彩鲜艳。通过SSD1306芯片的控制,我们能够实现各种图形和文字的显示,满足嵌入式系统的需求。
claretttt 发表于 2025-2-6 11:03 | 显示全部楼层
虽然 SSD1306 有开源驱动代码,但在实际应用中,可能需要根据 AT - START - L021 的特点和具体需求对代码进行优化,以提高显示性能和效率。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

13

主题

110

帖子

0

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