打印
[AIROC™ 蓝牙]

【英飞凌CYW20829测评】5.I2C驱动OLED和读取温湿度

[复制链接]
2220|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
I2C总线是Philips公司在八十年代初推出的一种串行、半双工的总线,主要用于近距离、低速的芯片之间的通信;I2C总线有两根双向的信号线,一根数据线SDA用于收发数据,一根时钟线SCL用于通信双方时钟的同步。连接在 I2C总线上的器件分为主机和从机,主机有权发起和结束一次通信,从机只能被动呼叫,每个连接到I2C总线上的器件都有一个唯一的地址。

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

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

cyhal_i2c_t i2c_obj;
void APP_I2CInit(void)
{
    cyhal_i2c_cfg_t cfg = {
            .address = 0,
            .is_slave = false,
            .frequencyhal_hz = 100000,
    };
    cyhal_i2c_init(&i2c_obj,CYBSP_I2C_SDA,CYBSP_I2C_SCL,NULL);
    cyhal_i2c_configure(&i2c_obj,&cfg);
}

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

uint8_t YUYY_OLED_SSD1315_I2CSendDatas(YUYY_OLED_SSD1315_DEV_Type *oled_ssd1315_dev,uint8_t cmd,uint8_t *datas,uint8_t datalen)
{
    uint8_t err = 0;
    err = cyhal_i2c_master_mem_write(oled_ssd1315_dev->i2cx,YUYY_OLED_SSD1315_I2C_ADDR,cmd,1,datas,datalen,1000);
    return err;
}

uint8_t YUYY_OLED_SSD1315_SendCmds(YUYY_OLED_SSD1315_DEV_Type *oled_ssd1315_dev,uint8_t *cmds,uint8_t cmdlen)
{
    return YUYY_OLED_SSD1315_I2CSendDatas(oled_ssd1315_dev,0x00,cmds,cmdlen);
}

uint8_t YUYY_OLED_SSD1315_SendDatas(YUYY_OLED_SSD1315_DEV_Type *oled_ssd1315_dev,uint8_t *datas,uint8_t datalen)
{
    return YUYY_OLED_SSD1315_I2CSendDatas(oled_ssd1315_dev,0x40,datas,datalen);
}

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

运行效果

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

DHTC12驱动代码
#define DHTC12_I2C_ADDR 0x44
typedef struct
{
    uint8_t inited;
    cyhal_i2c_t *i2cx;
}YUYY_DHTC12_DEV_Type;
static uint16_t HumA,HumB;

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

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

uint8_t YUYY_DHTC12_ReadCmd(YUYY_DHTC12_DEV_Type *dhtc12_dev,uint16_t cmd,uint8_t *rdatas,uint8_t rlen)
{
    uint8_t regs[2];
    regs[0] = (cmd>>8)&0xFF;
    regs[1] = cmd&0xFF;
    cyhal_i2c_master_write(dhtc12_dev->i2cx,DHTC12_I2C_ADDR,regs,2,1000,false);
    return cyhal_i2c_master_read(dhtc12_dev->i2cx,DHTC12_I2C_ADDR,rdatas,rlen,1000,true);
}

//初始化,获取湿度运算系数
uint8_t YUYY_DHTC12_Init(YUYY_DHTC12_DEV_Type *dhtc12_dev)
{
    uint8_t x,err = 0,retry = 3;
    dhtc12_dev->inited = 0;
    //复位传感器
    err = YUYY_DHTC12_WriteCmd(dhtc12_dev,0x30A2);
    err = YUYY_DHTC12_ReadCmd(dhtc12_dev,0xD208,&x,1);
    HumA = (x<<8)&0xFF00;
    err = YUYY_DHTC12_ReadCmd(dhtc12_dev,0xD209,&x,1);
    HumA |= x;
   
    err = YUYY_DHTC12_ReadCmd(dhtc12_dev,0xD20A,&x,1);
    HumB = (x<<8)&0xFF00;
    err = YUYY_DHTC12_ReadCmd(dhtc12_dev,0xD20B,&x,1);
    HumB |= x;
    //HumA=0x7168;  HumB=0x2D73;
    //ReadDatSH[6]={0xF3, 0xA9, 0xC0, 0x41, 0xB4, 0x87}
    //27.6 48.4%
    dhtc12_dev->inited = 1;
    return 0;
}

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

uint8_t YUYY_DHTC12_CheckCrc(uint8_t Data[], uint8_t nbrOfBytes)
{
    uint8_t crc = 0xff; //0
    uint8_t byteCtr,Bit;
    //calculates 8-Bit checksum with given polynomial
    for (byteCtr = 0; byteCtr < nbrOfBytes; ++byteCtr)
    {
        crc ^= (Data[byteCtr]);
        for (Bit = 8; Bit > 0; --Bit)
        {
            if (crc & 0x80)
                crc = (crc << 1) ^ POLYNOMIAL;
            else
                crc = (crc << 1);
        }
    }
    if (crc != Data[nbrOfBytes])
    {
        Data[nbrOfBytes] = crc;
        return 0x01;
    }
    else
        return 0;
}

//单次触发温湿度测量
uint8_t YUYY_DHTC12_ReadHT(YUYY_DHTC12_DEV_Type *dhtc12_dev,int16_t *tem,int16_t *hum)
{
    uint8_t i=0,errRe,ReadDatSH[6],CalCRC[3],errorflag=0;
    int16_t TemBuf;
    uint16_t CapBuf;
    errRe = YUYY_DHTC12_WriteCmd(dhtc12_dev,0x2C10);
    if(errRe)
        errRe = YUYY_DHTC12_WriteCmd(dhtc12_dev,0x2C10);
    if(errRe)
    {
        return 0x10|errRe; //发送命令失败
    }
   
    Cy_SysLib_Delay(100);
    errRe = YUYY_DHTC12_ReadDatas(dhtc12_dev,ReadDatSH,6);

    if(errRe)
    {
        return 0x20|errRe; //接收数据失败
    }
    CalCRC[0] = ReadDatSH[0];
    CalCRC[1] = ReadDatSH[1];
    CalCRC[2] = ReadDatSH[2];
    errorflag = YUYY_DHTC12_CheckCrc(CalCRC,2);
    if(errorflag==0)
    {
        TemBuf = (int16_t)(((ReadDatSH[0]<<8)&0xFF00)|ReadDatSH[1]);
        *tem = TemBuf*10/256 + 400;
    }
    CalCRC[0] = ReadDatSH[3];
    CalCRC[1] = ReadDatSH[4];
    CalCRC[2] = ReadDatSH[5];
    errorflag <<= 1;
    errorflag |= YUYY_DHTC12_CheckCrc(CalCRC,2);
    if(errorflag==0)
    {
        CapBuf = (uint16_t)(((ReadDatSH[3]<<8)&0xFF00)|ReadDatSH[4]);
        *hum = (CapBuf-HumB)*600/(HumA-HumB)+300;
        //20℃为5个湿度点  即1℃为0.25个湿度点  0.1℃为0.025
        *hum = *hum+ 2.5*(*tem-250);
        if(*hum>1000)
            *hum = 999;
        else if(*hum<0)
            *hum = 0;
    }
    return errorflag;   
}

初始化,读取温湿度并显示在OLED上
YUYY_DHTC12_DEV_Type dhtc12_dev;
void APP_DHTC12Init(void)
{
    dhtc12_dev.i2cx = &i2c_obj;
    YUYY_DHTC12_Init(&dhtc12_dev);
}
int main(void)
{
    cy_rslt_t result;
    uint8_t printf_count = 0;
    int16_t temp,humi;
    char out[20];
    result = cybsp_init();
    if (result != CY_RSLT_SUCCESS)
    {
        CY_ASSERT(0);
    }
    app_uart_init();
    APP_I2CInit();
    printf("APP Start\n");
    /* Enable global interrupts */
    __enable_irq();

    for (;;)
    {
        Cy_SysLib_Delay(1000);
        printf_count += 1;
        if(!YUYY_DHTC12_ReadHT(&dhtc12_dev,&temp,&humi))
        {
            sprintf(out,"T:%03.1f  H:%03.1f%%\n",temp/10.0,humi/10.0);
            YUYY_OLED_SSD1315_DisplayString8x16(&oled_dev,0,4,0,out);
        }
    }
}

运行效果

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

使用特权

评论回复
沙发
地瓜patch| | 2024-6-27 21:13 | 只看该作者
iic最方便,难度低,普及率很高

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

145

主题

695

帖子

6

粉丝