CC2530连接AM2321温湿传感器得不到数据
时间:10-02
整理:3721RD
点击:
CC2530连接了AM2321传感器模块,由于是模块化了的板子,所以硬件连接没有任何错误,串口连接电脑,程序上按照AM2321数据手册上的时序图写了Read_Sensor读取函数,只要一进入Read_Sensor(void)读取数据的函数中就会因为传感器没有电平变化响应而跳出,无法获得数据。
#include <iocc2530.h> #include <string.h> #define uint unsigned int #define uchar unsigned char #define Sensor_SDA P0_4 //定义P0.4为AM2321的数据口 #define SDADirOut P0DIR|=0x10; //xxxx1M01 #define SDADirIn P0DIR&=0x10; #define COM_R MDP0_4 unsigned char Sensor_Data[5]={0x00,0x00,0x00,0x00,0x00};//定义温湿度传感器数据存放区。 unsigned char Sensor_Check; //温湿度传感器校验和,判断读取的温湿度数据是否正确。 unsigned char Sensor_AnswerFlag; //温湿度传感器收到起始标志位 unsigned char Sensor_ErrorFlag; //读取传感器错误标志 unsigned char Ascii_buffer[10] = {'0','1','2','3','4','5','6','7','8','9'}; unsigned char mbus_regi[20] = {'H',':','0','0','.','0','%','R','H',',','T',':','0','0','.','0'}; unsigned int RH_Data;//定义湿度值,起到中转作用,因为其数值一般大于255,所以声明为int 类型 unsigned int T_Data;//定义温度值,起到中转作用 ,因为其数值一般大于255,所以声明为int 类型 unsigned int Sys_CNT; unsigned int Tmp; char Recdata[100]; //接收数据缓存 uchar RXflag = 1; //接收完成标志 uint datanumber = 0; //接收数据的长度 void delay_10us(uint n); void delay_1s(uint n); unsigned char Read_SensorData(void); //声明读取AM2321数据函数 unsigned char Read_Sensor(void); //声明读取AM2321温湿度数据函数 void Delay(uint n); void InitLED(void); void initUART0(void); void delay_1us(uint microSecs) { while(microSecs--) { /* 32 NOPs == 1 usecs 因为延时还有计算的缘故,用了31个nop*/ asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); } } void Delay(uint n) //延时 如需精确延时请用示波器辅助调试 { uint i,j; for(j = 0; j < 10 ; j++) { for(i = 0; i < n ; i++); } } void delay_10us(uint n) { uint tt,yy; for(tt=0;tt<n;tt++); for(yy=310;yy>0;yy--)asm("NOP"); } void delay_1s(uint n) { uint tt,ulloop=1000; for(tt=n;tt>0;tt--); for(ulloop=1000;ulloop>0;ulloop--)delay_1us(1000); } void initUART0(void)//初始化串口0函数 { CLKCONCMD &= ~0x40; //设置系统时钟源为32MHZ晶振 while(CLKCONSTA & 0x40); //等待晶振稳定 CLKCONCMD &= ~0x47; //设置系统主时钟频率为32MHZ PERCFG = 0x00; //位置1 P0口 P0SEL = 0x3C; //P0用作串口 P2DIR &= ~0XC0; //P0优先作为UART0 U0CSR |= 0xC0; //串口设置为UART方式 U0GCR |= 8; //波特率设为9600 U0BAUD |= 56; UTX0IF = 1; //UART0 TX中断标志初始置位1 U0CSR |= 0X40; //允许接收 IEN0 |= 0x04; //开总中断,接收中断 EA = 1; } void uartbyte(char dat) { U0DBUF=dat; while(UTX0IF==0); UTX0IF=0; } void uartstring(char*a) { for(;*a!=0;a++) { uartbyte(*a); } } void main(void) { int i; initUART0(); SDADirIn; Sensor_SDA=1; //SDA数据线由上拉电阻拉高一直保持高电平,初始化数据总线。 while(1) { delay_1s(1); delay_1us(30000); delay_1us(30000); delay_1us(30000); delay_1us(30000); //延时0.1s Read_Sensor(); // 读取传感器数据 if(Sensor_Data[4] == (Sensor_Data[0]+ Sensor_Data[1]+Sensor_Data[2]+Sensor_Data[3]))//判断温湿度校验值是否相等,见AM2321数据手册P17. { RH_Data = (Sensor_Data[0] * 256) + Sensor_Data[1];//保存湿度值,见AM2321数据手册P17 T_Data = (Sensor_Data[2] * 256) + Sensor_Data[3];//保存温度值,见AM2321数据手册P17 mbus_regi[2] = Ascii_buffer[RH_Data/100]; //取得湿度十位值 mbus_regi[3] = Ascii_buffer[(RH_Data%100)/10];//取得湿度个位值 mbus_regi[5] = Ascii_buffer[RH_Data%10];//取得湿度小数值 mbus_regi[12] = Ascii_buffer[T_Data/100];//取得温度十位值 mbus_regi[13] = Ascii_buffer[(T_Data%100)/10];//取得温度个位值 mbus_regi[15] = Ascii_buffer[T_Data%10];//取得温度小数值 for(i = 0; i < 16; i++) { uartbyte(mbus_regi[i]); } uartbyte('\r'); uartbyte('\n'); } } } #pragma vector = URX0_VECTOR __interrupt void UART0_ISR(void)//串口接收中断处理程序:将接收到的数据赋值给变量temp. { uchar temp; temp = U0DBUF; if(temp == '#'||temp == '\n') //‘#’结束标识符 { Recdata[datanumber++] = '\n'; RXflag = 1; //接收完成 } else Recdata[datanumber++] = temp; URX0IF = 0; //清中断标志 } unsigned char Read_SensorData(void) //功能描述:读取单字节的AM2321的数据 { int cnt; unsigned char i; unsigned char buffer,tmp; buffer = 0; for(i=0;i<8;i++) { cnt=0; while(!Sensor_SDA) //检测上次低电平是否结束 { if(++cnt>290) { uartbyte('X'); break; } } //延时Min=26us Max50us 跳过数据"0" 的高电平 delay_1us(35);//延时30us tmp =0; if(Sensor_SDA)//延时30us后如果数据口还是高,则该位为1,否则为0,见P19 { tmp = 1; } cnt =0; while(Sensor_SDA) //等待高电平 结束 { if(++cnt >= 200){ uartbyte('V'); break;} } buffer <<=1; //移位,使得数据的最低位准备接收下一位 buffer |= tmp;//把本次接收到的位加入到数据中 // uartbyte(buffer); } return buffer;//返回单字节数据 } unsigned char Read_Sensor(void) //功能描述:读取AM2321的温湿度及校验值放在Sensor_Data[]中。 { unsigned char i,j; P0SEL &= 0XEF; SDADirOut; P0_4 = 0;//起始信号拉低,见AM2321数据手册P18 delay_1us(1000); //延时3Ms,当然一般1ms就可以了。 P0_4 = 1; //拉高,释放总线 SDADirIn; delay_1us(30); //延时30us //Sensor_AnswerFlag = 0; // 传感器响应标志 if(P0_4 ==0)//从高电平到低电平经过30us(大于20us)是否为低 { //如果为低,那么传感器发出响应信号 Sensor_AnswerFlag = 1;//收到起始信号 Sys_CNT = 0;//判断从机是否发出 80us 的低电平响应信号是否结束 //delay_1s(3); uartbyte('A'); while((!P0_4)) //等待传感器响应信号80us的低电平结束 { for(j=0;j<8;j++)delay_1us(10); // Sensor_SDA = 0; if(j>=8) //防止进入死循环 { Sensor_ErrorFlag = 1; //Sensor_SDA uartbyte('B'); /****接到'B'说明传感器没有响应*****/ uartbyte('\t'); return 0; } } j=0; Sys_CNT = 0; //判断从机是否发出 80us 的高电平,如发出则进入数据接收状态 while((Sensor_SDA))//等待传感器响应信号80us的高电平结束 { for(j=0;j<8;j++)delay_1us(10); // Sensor_SDA = 0; if(j>=8)//防止进入死循环 { uartbyte('C'); Sensor_ErrorFlag = 1; return 0; } } // 数据接收 传感器共发送40位数据 // 即5个字节 高位先送 5个字节分别为湿度高位 湿度低位 温度高位 温度低位 校验和 // 校验和为:湿度高位+湿度低位+温度高位+温度低位 for(i=0;i<5;i++) { Sensor_Data[i] = Read_SensorData(); uartbyte('M'); } if((Sensor_Data[0]+Sensor_Data[1]+Sensor_Data[2]+Sensor_Data[3])!=Sensor_Data[4]) { for(i=0;i<5;i++) { //Am2321_Data[i] = 0x02; } } } else { Sensor_AnswerFlag = 0; uartbyte('Q');// 未收到传感器响应 } return 1; }
i2c传感器地址是多少?主要检查i2c时序以及引脚是否接上拉电阻?
单总线读的传感器,引脚上拉没问题,提供的案例能在协议栈里面读到。
问题已解决,CC2530裸机单总线读取传感器数据对延时要求特别高,望各位小心。 网上有人用示波器测试了2530裸机延时相关数据: void Delay_us(uint16 value){ while (value--) { asm("NOP"); //一个指令周期占用一个时钟周期 asm("NOP"); asm("NOP"); } } 用示波器测试的不同的参数,其时间值如下表: 参数值 时间值 75 100us 130 170us 100 130us 也就是说value大概为8为延时1us左右。
单总线时序确实严格的,解决问题就好。