本帖最后由 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中用来测试片上的温度传感器的例程。工作是正常的,改变单片机的温度,数据会跟着发生变化。 程序的运行效果如下:
|