打印
[开发板]

体验CW32L010F8P6的I2C外设

[复制链接]
48|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 suncat0504 于 2024-11-20 19:20 编辑

CW32L010F8P6是武汉芯源生产的一种低功耗ARM Cortex M0+32位单片机。单片机内部集成了一个I2C控制器,可以以标准、快速、高速传输数据的方式完成I2C通讯。其主要特性:

● 支持主机发送 / 接收,从机发送 / 接收四种工作模式
● 支持时钟延展 ( 时钟同步 ) 和多主机通信冲突仲裁
● 支持标准 (100Kbps)/ 快速 (400Kbps)/ 高速 (1Mbps) 三种工作速率
● 支持 7bit 寻址功能
● 支持 3 个从机地址
● 支持广播地址
● 支持输入信号噪声过滤功能
● 支持中断状态查询功能
● 支持 SMBUS 超时检测
● 支持与工作电压低于 MCU 的器件通信(借助 VC)

因为I2C地址不同,可以在I2C总线上同时驱动SS1306驱动的OLED和I2C总线的BH1750,这是本次学习的主要内容。整个系统的电路构成:

1、CW32L010F8P6_StartKit开发板
2、OLED模块
3、BH1750实验中BH1750是I2C接口的一个模块:

电路构成简易图:

程序在I2C例程的基础上进行修改。开发板的I2C外设设置为主机收发模式(对OLED是主机发送,对BH1750是主机发送、主机接收),工作于1MHz的传输速率。

1、主机发送模式
图1、主机发送模式状态同步图


图2、主机发送模式流程和寄存器状态

根据以上资料,编写OLED的驱动程序。如果使用中断模式的处理I2C通讯数据的话,势必要根据中间通讯状态值,执行对应的处理,而且是各自独立的处理(中断和状态值分支处理),所以选择的是查询模式。OLED中核心的处理部分代码:

//发送一个字节

//向SSD1306写入一个字节。

//mode:数据/命令标志 0,表示命令;1,表示数据;

void OLED_WR_Byte(uint8_t dat,uint8_t mode) {

    uint8_t u8i = 0, u8State;

   

    // 发出开始信号

    I2C_GenerateSTART(CW_I2C1, ENABLE);

    while (1) {

        while (0 == I2C_GetIrq(CW_I2C1)) ;

        u8State = I2C_GetState(CW_I2C1);

        switch (u8State) {

            case 0x08:   //发送完START信号

                I2C_GenerateSTART(CW_I2C1, DISABLE);

                I2C_Send7bitAddress(CW_I2C1, OLED_ADDR, 0X00); //从设备地址发送

                break;

            case 0x18:   //发送完SLA+W信号,ACK已收到

                //   

                if(mode){

                    // 数据

                    I2C_SendData(CW_I2C1,0x40);

                } else {

                    // 指令

                    I2C_SendData(CW_I2C1,0x00);

                }

                break;

            

            case 0x28:   

                I2C_SendData(CW_I2C1, dat);

                u8i++;

                break;

            

            case 0x20:   //发送完SLA+W后从机返回NACK

               

            case 0x38:    //主机在发送 SLA+W 阶段或者发送数据阶段丢失仲裁  或者  主机在发送 SLA+R 阶段或者回应 NACK 阶段丢失仲裁

                I2C_GenerateSTART(CW_I2C1, ENABLE);

                break;

            

            case 0x30:   //发送完一个数据字节后从机返回NACK

                I2C_GenerateSTOP(CW_I2C1);

                break;

            

            default:

                break;

        }

        if (u8i > 1) {

            I2C_GenerateSTOP(CW_I2C1);// 发出停止信号

            I2C_ClearIrq(CW_I2C1);

            break;

        }

        I2C_ClearIrq(CW_I2C1);

    }

}

而BH1750的处理部分,虽然都是I2C通讯模式,但由于BH1750的控制简单,其工作流程为以下方式:
1、初始化BH1750,执行PowerOn,发送指令0x01;
2、命令BH1750进行高分辨率连续测量方式,发送命令0x10;
3、在2执行完成后,延迟180mS以上后,执行读操作,接收来自BH1750的两字节数据,以此计算出光强。
按照这个流程,对BH1750的操作很简单,不需要向驱动OLED那样操作。其整个流程:
uint8_t bh1750cmd[] = {0x01};

    uint8_t bh1750dat[8] = {0,0,0,0,0,0,0,0};

    float val = 0;



        // BH1750(I2C方式)

        bh1750cmd[0] = 0x01;  // PowerOn

        I2C_MasterSendDataToSlave(CW_I2C1, I2C_BH1750ADDR, bh1750cmd, 1);

        bh1750cmd[0] = 0x10;  // 高分辨率连续测量命令=0x10

        I2C_MasterSendDataToSlave(CW_I2C1, I2C_BH1750ADDR, bh1750cmd, 1);   

        DelayMs(200);        

        I2C_MasterRecDataFromSlave(CW_I2C1, I2C_BH1750ADDR, bh1750dat, 2);

        val = (bh1750dat[0]>>8 | bh1750dat[1])/1.2;

        printf("\r\nBH1750 Value = %f", val);

        OLED_ShowNum(76, 0, (int)val, 6, 16);


因此不需要建立专门的处理文件了,只需将上述代码嵌入到主程序中就行。可见使用I2C外设和库函数,使得利用I2C的通讯变得非常方便了。


话说本来打算只用更简单的方式,使用TEMT6000,并利用ADC处理获取光强数据。对光强的处理,也没打算用精确数据方式,只要满足阈值的变化,用来驱动马达即可。可万万没想到,CW32L010的ADC例程似乎没有正常干活。对于选定的ADC输入端的电压变化,AEDC转换没有任何反应,所以只好使用BH1750来测量了。但是AC中用来测试片上的温度传感器的例程。工作是正常的,改变单片机的温度,数据会跟着发生变化。

程序的运行效果如下:







使用特权

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

本版积分规则

认证:大连伊飞特信息技术有限公司软件工程师
简介:本人于1993年毕业于大连理工大学。毕业后从事单片机开发工作5年,之后转入软件开发工作至今。

123

主题

3734

帖子

5

粉丝