返回列表 发新帖我要提问本帖赏金: 50.00元(功能说明)

[AT32F405] AT32F405RCT7-7之硬件IIC驱动OLED

[复制链接]
4573|7
 楼主| shendu0032 发表于 2024-4-25 09:29 | 显示全部楼层 |阅读模式
在上一篇文章中介绍AT32F405RCT7-7之软件IIC驱动OLED通过软件模拟IIC通讯波形来实现数据传输。但是软件IIC传输速率不如硬件IIC。这次使用AT32自带的硬件IIC来驱动OLED。
使用AT Work Bench软件新建硬件IIC的测试工程,配置IIC的模式和参数以及对应IIC引脚的模式和参数。
IIC配置.png GPIO配置.png
同时需要开启DMA传输,因为在后面添加i2c_application.c和i2c_application.h文件中需要DMA的库函数,或者可以手动添加at32f402_405_dma.c库文件。
开启DMA传输.png
之后是系统时钟设置,可以选择使用外部时钟或者内部时钟。最后生成代码。
打开生成的MDK工程,添加i2c_application.c和i2c_application.h文件,这两个文件可以在生成代码的文件夹的HARD_IIC\middlewares\i2c_application_library路径下找到,跟上一篇同样新建OLED和delay的.c和.h文件。在at32f402_405_wk_config.c文件中系统自动生成IIC2初始化代码
  1. void wk_i2c2_init(void)
  2. {
  3.   /* add user code begin i2c2_init 0 */

  4.   /* add user code end i2c2_init 0 */

  5.   gpio_init_type gpio_init_struct;

  6.   gpio_default_para_init(&gpio_init_struct);

  7.   /* add user code begin i2c2_init 1 */

  8.   /* add user code end i2c2_init 1 */

  9.   /* configure the SCL pin */
  10.   gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
  11.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  12.   gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  13.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
  14.   gpio_init_struct.gpio_pins = SCL_PIN;
  15.   gpio_init(SCL_GPIO_PORT, &gpio_init_struct);

  16.   gpio_pin_mux_config(SCL_GPIO_PORT, GPIO_PINS_SOURCE0, GPIO_MUX_4);

  17.   /* configure the SDA pin */
  18.   gpio_init_struct.gpio_out_type = GPIO_OUTPUT_OPEN_DRAIN;
  19.   gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  20.   gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  21.   gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
  22.   gpio_init_struct.gpio_pins = SDA_PIN;
  23.   gpio_init(SDA_GPIO_PORT, &gpio_init_struct);

  24.   gpio_pin_mux_config(SDA_GPIO_PORT, GPIO_PINS_SOURCE1, GPIO_MUX_4);

  25.   i2c_init(I2C2, 0, 0x30D08080);
  26.   i2c_own_address1_set(I2C2, I2C_ADDRESS_MODE_7BIT, 0x0);
  27.   i2c_ack_enable(I2C2, TRUE);
  28.   i2c_clock_stretch_enable(I2C2, TRUE);
  29.   i2c_general_call_enable(I2C2, FALSE);

  30.   i2c_enable(I2C2, TRUE);

  31.   /* add user code begin i2c2_init 2 */

  32.   /* add user code end i2c2_init 2 */
  33. }
我们只需要修改Write_IIC_Byte,Write_IIC_Data,Write_IIC_Command函数即可
  1. void Write_IIC_Byte(uint8_t IIC_Byte)
  2. {
  3.   i2c_status_type i2c_status;
  4.   uint8_t buff[2] = {0};
  5.         buff[0] = IIC_Byte;
  6.         i2c_status = i2c_master_transmit(&hi2cx, I2Cx_ADDRESS, buff, 1, 1000);
  7.         if(i2c_status != I2C_OK)
  8.         {
  9.                 printf("erro send %d",i2c_status);
  10.         }

  11. }
  12. //==================================================================================================
  13. //  函数功能: IIC外设驱动函数部分
  14. //  函数标记: Write_IIC_Command
  15. //  函数说明: 无

  16. void Write_IIC_Command(uint8_t IIC_Command)
  17. {
  18.    i2c_status_type i2c_status;
  19.    uint8_t buff[2] = {0};
  20.         buff[0] = 0x00;
  21.         buff[1] = IIC_Command;
  22.         i2c_status = i2c_master_transmit(&hi2cx, I2Cx_ADDRESS, buff, 2, 1000);
  23.         if(i2c_status != I2C_OK)
  24.         {
  25.                 printf("erro send %d",i2c_status);
  26.         }
  27. }
  28. //==================================================================================================
  29. //  函数功能: IIC外设驱动函数部分
  30. //  函数标记: Write_IIC_Data
  31. //  函数说明: 无
  32. void Write_IIC_Data(uint8_t IIC_Data)
  33. {
  34.     i2c_status_type i2c_status;
  35.     uint8_t buff[2] = {0};
  36.         buff[0] = 0x40;
  37.         buff[1] = IIC_Data;
  38.         i2c_status = i2c_master_transmit(&hi2cx, I2Cx_ADDRESS, buff, 2, 1000);
  39.         if(i2c_status != I2C_OK)
  40.         {
  41.                 printf("erro send %d",i2c_status);
  42.         }
  43. }
之后初始化OLED
  1. <blockquote>static void i2c_config_init(void)
OLED的数字,字符,字符串以及汉字等的驱动函数保持不变
  1. void OLED_Set_Pos(unsigned char x, unsigned char y)
  2. {         OLED_WR_Byte(0xb0+y,OLED_CMD);
  3.         OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
  4.         OLED_WR_Byte((x&0x0f),OLED_CMD);
  5. }             
  6. //开启OLED显示   
  7. void OLED_Display_On(void)
  8. {
  9.         OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
  10.         OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
  11.         OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
  12. }
  13. //关闭OLED显示     
  14. void OLED_Display_Off(void)
  15. {
  16.         OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
  17.         OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
  18.         OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
  19. }                                            
  20. //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!          
  21. void OLED_Clear(void)  
  22. {  
  23.         uint8_t i,n;                    
  24.         for(i=0;i<8;i++)  
  25.         {  
  26.                 OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
  27.                 OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
  28.                 OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
  29.                 for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
  30.         } //更新显示
  31. }
  32. void OLED_On(void)  
  33. {  
  34.         uint8_t i,n;                    
  35.         for(i=0;i<8;i++)  
  36.         {  
  37.                 OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
  38.                 OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
  39.                 OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
  40.                 for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA);
  41.         } //更新显示
  42. }
  43. //在指定位置显示一个字符,包括部分字符
  44. //x:0~127
  45. //y:0~63
  46. //mode:0,反白显示;1,正常显示                                 
  47. //size:选择字体 16/12
  48. void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size)
  49. {             
  50.         unsigned char c=0,i=0;       
  51.                 c=chr-' ';//得到偏移后的值                       
  52.                 if(x>Max_Column-1){x=0;y=y+2;}
  53.                 if(Char_Size ==16)
  54.                         {
  55.                         OLED_Set_Pos(x,y);       
  56.                         for(i=0;i<8;i++)
  57.                         OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
  58.                         OLED_Set_Pos(x,y+1);
  59.                         for(i=0;i<8;i++)
  60.                         OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
  61.                         }
  62.                         else {       
  63.                                 OLED_Set_Pos(x,y);
  64.                                 for(i=0;i<6;i++)
  65.                                 OLED_WR_Byte(F6x8[c][i],OLED_DATA);
  66.                                
  67.                         }
  68. }
  69. //m^n函数
  70. uint32_t oled_pow(uint8_t m,uint8_t n)
  71. {
  72.         uint32_t result=1;         
  73.         while(n--)result*=m;   
  74.         return result;
  75. }                                  
  76. //显示2个数字
  77. //x,y :起点坐标         
  78. //len :数字的位数
  79. //size:字体大小
  80. //mode:模式        0,填充模式;1,叠加模式
  81. //num:数值(0~4294967295);                           
  82. void OLED_ShowNumber(uint8_t x,uint8_t y,uint32_t        num,uint8_t len,uint8_t size2)
  83. {                
  84.         uint8_t t,temp;
  85.         uint8_t enshow=0;                                                  
  86.         for(t=0;t<len;t++)
  87.         {
  88.                 temp=(num/oled_pow(10,len-t-1))%10;
  89.                 if(enshow==0&&t<(len-1))
  90.                 {
  91.                         if(temp==0)
  92.                         {
  93.                                 OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
  94.                                 continue;
  95.                         }else enshow=1;
  96.                           
  97.                 }
  98.                  OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
  99.         }
  100. }
  101. //显示一个字符号串
  102. void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t Char_Size)
  103. {
  104.         while (*chr!='\0')
  105.         {                OLED_ShowChar(x,y,*chr,Char_Size);
  106.                         x+=8;
  107.                 if(x>120){x=0;y+=2;}
  108.                         chr++;
  109.         }
  110. }
  111. //显示汉字
  112. void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no)
  113. {                                  
  114.         uint8_t t,adder=0;
  115.         OLED_Set_Pos(x,y);       
  116.     for(t=0;t<16;t++)
  117.                 {
  118.                                 OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);
  119.                                 adder+=1;
  120.      }       
  121.                 OLED_Set_Pos(x,y+1);       
  122.     for(t=0;t<16;t++)
  123.                         {       
  124.                                 OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);
  125.                                 adder+=1;
  126.       }                                       
  127. }
  128. /***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
  129. void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
  130. {        
  131. unsigned int j=0;
  132. unsigned char x,y;
  133.   
  134.   if(y1%8==0) y=y1/8;      
  135.   else y=y1/8+1;
  136.         for(y=y0;y<y1;y++)
  137.         {
  138.                 OLED_Set_Pos(x0,y);
  139.     for(x=x0;x<x1;x++)
  140.             {      
  141.                     OLED_WR_Byte(BMP[j++],OLED_DATA);                   
  142.             }
  143.         }
  144. }
  145. void OLED_Float(unsigned char Y,unsigned char X,double real,unsigned char N)
  146. {
  147.    unsigned char   i_Count=1;
  148.    unsigned char   n[12]={0};
  149.    long   j=1;  
  150.    int    real_int=0;
  151.    double decimal=0;
  152.    unsigned int   real_decimal=0;
  153.    if(real<0)
  154.          {
  155.                  real_int=(int)(-real);
  156.          }
  157.          else
  158.          {
  159.                  real_int=(int)real;
  160.    }
  161.          decimal=real-real_int;
  162.    real_decimal=decimal*1e4;
  163.    while(real_int/10/j!=0)
  164.    {
  165.       j=j*10;i_Count++;  
  166.    }
  167.    n[0]=(real_int/10000)%10;
  168.    n[1]=(real_int/1000)%10;
  169.    n[2]=(real_int/100)%10;
  170.    n[3]=(real_int/10)%10;
  171.    n[4]=(real_int/1)%10;
  172.    n[5]='.';
  173.    n[6]=(real_decimal/1000)%10;
  174.    n[7]=(real_decimal/100)%10;
  175.    n[8]=(real_decimal/10)%10;
  176.    n[9]=real_decimal%10;
  177.    n[6+N]='\0';
  178.    for(j=0;j<10;j++) n[j]=n[j]+16+32;
  179.          if(real<0)
  180.          {                 
  181.                  i_Count+=1;
  182.                  n[5-i_Count]='-';
  183.          }
  184.    n[5]='.';
  185.    n[6+N]='\0';   
  186.    OLED_ShowString(X,Y,&n[5-i_Count],12);
  187. }

  188. void OLED_Float2(unsigned char Y,unsigned char X,double real,unsigned char N1,unsigned char N2)
  189. {
  190.    unsigned char   i_Count=1;
  191.    unsigned char   n[12]={0};
  192.    long   j=1;  
  193.    unsigned int   real_int=0;
  194.    double decimal=0;
  195.    unsigned int   real_decimal=0;
  196.    X=X*8;
  197.    real_int=(int)real;
  198.    //Dis_Num(2,0,real_int,5);
  199.    decimal=real-real_int;
  200.    real_decimal=decimal*1e4;
  201.    //Dis_Num(2,6,real_decimal,4);
  202.    while(real_int/10/j!=0)
  203.    {
  204.       j=j*10;i_Count++;  
  205.    }
  206.    n[0]=(real_int/10000)%10;
  207.    n[1]=(real_int/1000)%10;
  208.    n[2]=(real_int/100)%10;
  209.    n[3]=(real_int/10)%10;

  210.    n[5]='.';
  211.    n[6]=(real_decimal/1000)%10;
  212.    n[7]=(real_decimal/100)%10;
  213.    n[8]=(real_decimal/10)%10;
  214.    n[9]=real_decimal%10;
  215.    n[6+N2]='\0';
  216.    for(j=0;j<10;j++) n[j]=n[j]+16+32;
  217.    n[5]='.';
  218.    n[6+N2]='\0';   
  219.    OLED_ShowString(X,Y,&n[5-N1],12);
  220. }

  221. void OLED_Num2(unsigned char x,unsigned char y, int number)
  222. {
  223.         unsigned char shi,ge;
  224.               int num =number;
  225.         if(num<0)
  226.         {
  227.                 num=-num;
  228.                 shi=num%100/10;
  229.     ge=num%10;
  230.           OLED_fuhao_write(x,y,13);
  231.     OLED_Num_write(x+1,y,shi);
  232.     OLED_Num_write(x+2,y,ge);
  233.   }
  234.   else
  235.         {

  236.                 shi=num%100/10;
  237.     ge=num%10;
  238.                 OLED_fuhao_write(x,y,11);
  239.     OLED_Num_write(x+1,y,shi);
  240.     OLED_Num_write(x+2,y,ge);
  241.   }
  242.         
  243. }

  244. void OLED_Num3(unsigned char x,unsigned char y,int number)
  245. {
  246.   unsigned char ge,shi,bai;
  247.         int num =number;
  248.         if(num<0)
  249.         {
  250.                     num=-num;
  251.                     OLED_fuhao_write(x,y,13); //显示-号
  252.         ge = num %10;
  253.         shi = num/10%10;
  254.         bai = num/100;
  255.         OLED_Num_write(x+3,y,ge);
  256.         OLED_Num_write(x+2,y,shi);
  257.         OLED_Num_write(x+1,y,bai);
  258.         }
  259.         else
  260.         {
  261.        OLED_fuhao_write(x,y,11);
  262.         ge = num %10;
  263.         shi = num/10 %10;
  264.         bai = num/100;
  265.         OLED_Num_write(x+3,y,ge);
  266.         OLED_Num_write(x+2,y,shi);
  267.         OLED_Num_write(x+1,y,bai);
  268.   }
  269. }

  270. void OLED_Num4(unsigned char x,unsigned char y, int number)
  271. {
  272.         unsigned char qian,bai,shi,ge;
  273.         int num =number;
  274.         if(num<0)
  275.         {
  276.                 num=-num;
  277.         }
  278.         qian=num/1000;
  279.         bai=num%1000/100;
  280.         shi=num%100/10;
  281.         ge=num%10;

  282.         OLED_Num_write(x,y,qian);
  283.         OLED_Num_write(x+1,y,bai);
  284.         OLED_Num_write(x+2,y,shi);
  285.         OLED_Num_write(x+3,y,ge);
  286. }

  287. void OLED_Num_write(unsigned char x,unsigned char y,unsigned char asc)
  288. {
  289.         int i=0;
  290.         OLED_Set_Pos(x*6,y);
  291.         for(i=0;i<6;i++)
  292.         {
  293.                  OLED_WR_Byte(F6x8[asc+16][i],OLED_DATA);         
  294.         }
  295. }       
  296. void OLED_fuhao_write(unsigned char x,unsigned char y,unsigned char asc)
  297. {

  298.           int i=0;
  299.     OLED_Set_Pos(x*6,y);
  300.     for(i=0;i<6;i++)
  301.     {
  302.        OLED_WR_Byte(F6x8[asc][i],OLED_DATA);         
  303.     }

  304. }                       

  305. void OLED_Num5(unsigned char x,unsigned char y,unsigned int number)
  306. {
  307.         unsigned char wan,qian,bai,shi,ge;
  308.         wan=number/10000;
  309.                     qian = number%10000/1000;
  310.         bai=number%1000/100;
  311.         shi=number%100/10;
  312.         ge=number%10;
  313.         OLED_Num_write(x,y,wan);
  314.         OLED_Num_write(x+1,y,qian);
  315.         OLED_Num_write(x+2,y,bai);
  316.         OLED_Num_write(x+3,y,shi);
  317.                     OLED_Num_write(x+4,y,ge);
  318. }
之后在主函数添加必要的头文件和OLED_Init();OLED_Clear()函数,显示内容如下
  1.   OLED_ShowCHinese(0,2,0);
  2.          OLED_ShowCHinese(27,2,1);               
  3.    OLED_ShowCHinese(55,2,2);               
  4.    OLED_ShowCHinese(83,2,3);               
  5.    OLED_ShowCHinese(111,2,4);
  6.    OLED_ShowCHinese(23,0,5);
  7.    OLED_ShowCHinese(39,0,6);               
  8.    OLED_ShowCHinese(55,0,7);               
  9.    OLED_ShowCHinese(71,0,8);        
  10.    OLED_ShowCHinese(87,0,9);        
  11.    OLED_ShowString(8,4,"AT32F405RCT7-7",16);        
  12.    OLED_ShowString(31,6,"OLED",16);               
  13.    OLED_ShowCHinese(64,6,10);        
  14.    OLED_ShowCHinese(80,6,11);      
实验效果如图所示,拍照时会有频闪的问题,可能是硬件IIC的刷新率比较快,下一篇将制作动画来比较软件IIC和硬件IIC的刷新效果
效果.jpg

打赏榜单

ArteryMCU 打赏了 50.00 元 2024-06-07
理由:[F405开发板评测活动]内容优质

呐咯密密 发表于 2024-4-25 11:29 | 显示全部楼层
我也喜欢用硬件IIC,比较舒服

评论

就是有好多IIC实现过程中的状态判断让人很抓狂,动不动就死循环了  发表于 2024-4-25 13:31
WoodData 发表于 2024-4-25 14:38 | 显示全部楼层
学习学习
panghongfei 发表于 2024-6-25 08:21 | 显示全部楼层
能否提供I2C部分的代码 下载,谢谢
 楼主| shendu0032 发表于 2024-6-25 14:40 | 显示全部楼层
panghongfei 发表于 2024-6-25 08:21
能否提供I2C部分的代码 下载,谢谢

HARD_IIC.zip (3.51 MB, 下载次数: 43)


panghongfei 发表于 2024-6-25 18:08 | 显示全部楼层
焯! 发表于 2024-7-30 23:05 | 显示全部楼层
太有用了。我调IIC都快吐了,搞不明白为啥这个库写法怎么会像HAL,完全玩不懂。看了你这个说明一个小时就移植完成了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:总是缺乏自信,进进退退,走走停停,不停的自我耗损,又不断的为自我耗损而再耗损。

33

主题

261

帖子

7

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