[AIROC™ 蓝牙] 【英飞凌CYW20829测评】5.I2C驱动OLED和读取温湿度

[复制链接]
2602|1
 楼主| yuyy1989 发表于 2024-6-26 21:15 | 显示全部楼层 |阅读模式
I2C总线是Philips公司在八十年代初推出的一种串行、半双工的总线,主要用于近距离、低速的芯片之间的通信;I2C总线有两根双向的信号线,一根数据线SDA用于收发数据,一根时钟线SCL用于通信双方时钟的同步。连接在 I2C总线上的器件分为主机和从机,主机有权发起和结束一次通信,从机只能被动呼叫,每个连接到I2C总线上的器件都有一个唯一的地址。

开发板上引出的I2C接口是这个

不过使用了BSP后我们可以不用关心具体是哪个IO,这些都在BSP里定义好了,接下来使用CYW20829作为I2C主机点亮OLED屏幕,初始化I2C代码,配置为主机模式速度100k,初始化代码如下

  1. cyhal_i2c_t i2c_obj;
  2. void APP_I2CInit(void)
  3. {
  4.     cyhal_i2c_cfg_t cfg = {
  5.             .address = 0,
  6.             .is_slave = false,
  7.             .frequencyhal_hz = 100000,
  8.     };
  9.     cyhal_i2c_init(&i2c_obj,CYBSP_I2C_SDA,CYBSP_I2C_SCL,NULL);
  10.     cyhal_i2c_configure(&i2c_obj,&cfg);
  11. }

可以看到用了官方的BSP后初始化外设十分的简便,接下来实现OLED驱动代码,这个OLED是SSD1315驱动的,网上可以搜到具体的驱动代码,或者可以看我过往发的帖子,这里就不放完整代码了,只放上I2C通讯部分
  1. #define YUYY_OLED_SSD1315_I2C_ADDR 0x3C

  2. uint8_t YUYY_OLED_SSD1315_I2CSendDatas(YUYY_OLED_SSD1315_DEV_Type *oled_ssd1315_dev,uint8_t cmd,uint8_t *datas,uint8_t datalen)
  3. {
  4.     uint8_t err = 0;
  5.     err = cyhal_i2c_master_mem_write(oled_ssd1315_dev->i2cx,YUYY_OLED_SSD1315_I2C_ADDR,cmd,1,datas,datalen,1000);
  6.     return err;
  7. }

  8. uint8_t YUYY_OLED_SSD1315_SendCmds(YUYY_OLED_SSD1315_DEV_Type *oled_ssd1315_dev,uint8_t *cmds,uint8_t cmdlen)
  9. {
  10.     return YUYY_OLED_SSD1315_I2CSendDatas(oled_ssd1315_dev,0x00,cmds,cmdlen);
  11. }

  12. uint8_t YUYY_OLED_SSD1315_SendDatas(YUYY_OLED_SSD1315_DEV_Type *oled_ssd1315_dev,uint8_t *datas,uint8_t datalen)
  13. {
  14.     return YUYY_OLED_SSD1315_I2CSendDatas(oled_ssd1315_dev,0x40,datas,datalen);
  15. }

点亮OLED显示指定字符串
  1. YUYY_OLED_SSD1315_DEV_Type oled_dev;
  2. void APP_OledInit(void)
  3. {
  4.     oled_dev.i2cx = &i2c_obj;
  5.     YUYY_OLED_SSD1315_Init(&oled_dev);
  6.     YUYY_OLED_SSD1315_ClearScreen(&oled_dev);
  7.     YUYY_OLED_SSD1315_DisplayString8x16(&oled_dev,0,0,0," CYW20829 TEST");
  8.     YUYY_OLED_SSD1315_DisplayString8x16(&oled_dev,0,2,0,"    I2C OLED");
  9.     YUYY_OLED_SSD1315_DisplayString8x16(&oled_dev,0,4,0,"  bbs.21ic.com");
  10.     YUYY_OLED_SSD1315_DisplayString8x16(&oled_dev,0,6,0,"Code by yuyy1989");
  11. }

运行效果

I2C总线上可以挂载多个从设备,接下来就再增加个温湿度传感器,用I2C读取温湿度传感器的数据,并显示在OLED屏幕上
这里用的是DHTC12温湿度传感器,性能如下图

DHTC12驱动代码
  1. #define DHTC12_I2C_ADDR 0x44
  2. typedef struct
  3. {
  4.     uint8_t inited;
  5.     cyhal_i2c_t *i2cx;
  6. }YUYY_DHTC12_DEV_Type;
  7. static uint16_t HumA,HumB;

  8. uint8_t YUYY_DHTC12_WriteCmd(YUYY_DHTC12_DEV_Type *dhtc12_dev,uint16_t cmd)
  9. {
  10.     uint8_t regs[2];
  11.     regs[0] = (cmd>>8)&0xFF;
  12.     regs[1] = cmd&0xFF;
  13.     return cyhal_i2c_master_write(dhtc12_dev->i2cx,DHTC12_I2C_ADDR,regs,2,1000,true);
  14. }

  15. uint8_t YUYY_DHTC12_ReadDatas(YUYY_DHTC12_DEV_Type *dhtc12_dev,uint8_t *rdatas,uint8_t rlen)
  16. {
  17.     return cyhal_i2c_master_read(dhtc12_dev->i2cx,DHTC12_I2C_ADDR,rdatas,rlen,1000,true);
  18. }

  19. uint8_t YUYY_DHTC12_ReadCmd(YUYY_DHTC12_DEV_Type *dhtc12_dev,uint16_t cmd,uint8_t *rdatas,uint8_t rlen)
  20. {
  21.     uint8_t regs[2];
  22.     regs[0] = (cmd>>8)&0xFF;
  23.     regs[1] = cmd&0xFF;
  24.     cyhal_i2c_master_write(dhtc12_dev->i2cx,DHTC12_I2C_ADDR,regs,2,1000,false);
  25.     return cyhal_i2c_master_read(dhtc12_dev->i2cx,DHTC12_I2C_ADDR,rdatas,rlen,1000,true);
  26. }

  27. //初始化,获取湿度运算系数
  28. uint8_t YUYY_DHTC12_Init(YUYY_DHTC12_DEV_Type *dhtc12_dev)
  29. {
  30.     uint8_t x,err = 0,retry = 3;
  31.     dhtc12_dev->inited = 0;
  32.     //复位传感器
  33.     err = YUYY_DHTC12_WriteCmd(dhtc12_dev,0x30A2);
  34.     err = YUYY_DHTC12_ReadCmd(dhtc12_dev,0xD208,&x,1);
  35.     HumA = (x<<8)&0xFF00;
  36.     err = YUYY_DHTC12_ReadCmd(dhtc12_dev,0xD209,&x,1);
  37.     HumA |= x;
  38.    
  39.     err = YUYY_DHTC12_ReadCmd(dhtc12_dev,0xD20A,&x,1);
  40.     HumB = (x<<8)&0xFF00;
  41.     err = YUYY_DHTC12_ReadCmd(dhtc12_dev,0xD20B,&x,1);
  42.     HumB |= x;
  43.     //HumA=0x7168;  HumB=0x2D73;
  44.     //ReadDatSH[6]={0xF3, 0xA9, 0xC0, 0x41, 0xB4, 0x87}
  45.     //27.6 48.4%
  46.     dhtc12_dev->inited = 1;
  47.     return 0;
  48. }

  49. const uint16_t POLYNOMIAL = 0x131; //P(x)=x^8+x^5+x^4+1 = 100110001

  50. uint8_t YUYY_DHTC12_CheckCrc(uint8_t Data[], uint8_t nbrOfBytes)
  51. {
  52.     uint8_t crc = 0xff; //0
  53.     uint8_t byteCtr,Bit;
  54.     //calculates 8-Bit checksum with given polynomial
  55.     for (byteCtr = 0; byteCtr < nbrOfBytes; ++byteCtr)
  56.     {
  57.         crc ^= (Data[byteCtr]);
  58.         for (Bit = 8; Bit > 0; --Bit)
  59.         {
  60.             if (crc & 0x80)
  61.                 crc = (crc << 1) ^ POLYNOMIAL;
  62.             else
  63.                 crc = (crc << 1);
  64.         }
  65.     }
  66.     if (crc != Data[nbrOfBytes])
  67.     {
  68.         Data[nbrOfBytes] = crc;
  69.         return 0x01;
  70.     }
  71.     else
  72.         return 0;
  73. }

  74. //单次触发温湿度测量
  75. uint8_t YUYY_DHTC12_ReadHT(YUYY_DHTC12_DEV_Type *dhtc12_dev,int16_t *tem,int16_t *hum)
  76. {
  77.     uint8_t i=0,errRe,ReadDatSH[6],CalCRC[3],errorflag=0;
  78.     int16_t TemBuf;
  79.     uint16_t CapBuf;
  80.     errRe = YUYY_DHTC12_WriteCmd(dhtc12_dev,0x2C10);
  81.     if(errRe)
  82.         errRe = YUYY_DHTC12_WriteCmd(dhtc12_dev,0x2C10);
  83.     if(errRe)
  84.     {
  85.         return 0x10|errRe; //发送命令失败
  86.     }
  87.    
  88.     Cy_SysLib_Delay(100);
  89.     errRe = YUYY_DHTC12_ReadDatas(dhtc12_dev,ReadDatSH,6);

  90.     if(errRe)
  91.     {
  92.         return 0x20|errRe; //接收数据失败
  93.     }
  94.     CalCRC[0] = ReadDatSH[0];
  95.     CalCRC[1] = ReadDatSH[1];
  96.     CalCRC[2] = ReadDatSH[2];
  97.     errorflag = YUYY_DHTC12_CheckCrc(CalCRC,2);
  98.     if(errorflag==0)
  99.     {
  100.         TemBuf = (int16_t)(((ReadDatSH[0]<<8)&0xFF00)|ReadDatSH[1]);
  101.         *tem = TemBuf*10/256 + 400;
  102.     }
  103.     CalCRC[0] = ReadDatSH[3];
  104.     CalCRC[1] = ReadDatSH[4];
  105.     CalCRC[2] = ReadDatSH[5];
  106.     errorflag <<= 1;
  107.     errorflag |= YUYY_DHTC12_CheckCrc(CalCRC,2);
  108.     if(errorflag==0)
  109.     {
  110.         CapBuf = (uint16_t)(((ReadDatSH[3]<<8)&0xFF00)|ReadDatSH[4]);
  111.         *hum = (CapBuf-HumB)*600/(HumA-HumB)+300;
  112.         //20℃为5个湿度点  即1℃为0.25个湿度点  0.1℃为0.025
  113.         *hum = *hum+ 2.5*(*tem-250);
  114.         if(*hum>1000)
  115.             *hum = 999;
  116.         else if(*hum<0)
  117.             *hum = 0;
  118.     }
  119.     return errorflag;   
  120. }

初始化,读取温湿度并显示在OLED上
  1. YUYY_DHTC12_DEV_Type dhtc12_dev;
  2. void APP_DHTC12Init(void)
  3. {
  4.     dhtc12_dev.i2cx = &i2c_obj;
  5.     YUYY_DHTC12_Init(&dhtc12_dev);
  6. }
  7. int main(void)
  8. {
  9.     cy_rslt_t result;
  10.     uint8_t printf_count = 0;
  11.     int16_t temp,humi;
  12.     char out[20];
  13.     result = cybsp_init();
  14.     if (result != CY_RSLT_SUCCESS)
  15.     {
  16.         CY_ASSERT(0);
  17.     }
  18.     app_uart_init();
  19.     APP_I2CInit();
  20.     printf("APP Start\n");
  21.     /* Enable global interrupts */
  22.     __enable_irq();

  23.     for (;;)
  24.     {
  25.         Cy_SysLib_Delay(1000);
  26.         printf_count += 1;
  27.         if(!YUYY_DHTC12_ReadHT(&dhtc12_dev,&temp,&humi))
  28.         {
  29.             sprintf(out,"T:%03.1f  H:%03.1f%%\n",temp/10.0,humi/10.0);
  30.             YUYY_OLED_SSD1315_DisplayString8x16(&oled_dev,0,4,0,out);
  31.         }
  32.     }
  33. }

运行效果

除了以上的设备之外,还有很多其他的设备(例如气压传感器、EEPROM、LED驱动器等)可以使用I2C通讯控制,有兴趣的伙伴可以自行尝试

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
地瓜patch 发表于 2024-6-27 21:13 来自手机 | 显示全部楼层
iic最方便,难度低,普及率很高
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:同飞软件研发工程师
简介:制冷系统单片机软件开发,使用PID控制温度

168

主题

826

帖子

10

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