单片机温湿度传感器

  1 #include "reg52.h"
  2 #include <intrins.h>
  3  
  4 #define USE_T2 
  5 #define FOSC  12000000
  6 #define BAUD  9600  
  7  
  8 //端口位定义,可修改
  9 sbit SDA=P1^0;
 10 sbit SCL=P1^1;
 11  
 12 //内部数据定义
 13 #define IIC_Add 0xB8    //器件地址
 14 #define IIC_RX_Length 15
 15  
 16 unsigned char IIC_TX_Buffer[]={0x03,0x00,0x04}; //读温湿度命令(无CRC校验)
 17 unsigned char IIC_RX_Buffer[IIC_RX_Length] = {0x00};//读回的温湿度
 18  
 19 unsigned char Uart_RX_Buffer[30] = {0x00};
 20 unsigned char *String;
 21 unsigned char WR_Flag;
 22  
 23 //字符串定义
 24 #define S_Function  "Function: 03 04"
 25 #define S_Temp "Temp:"
 26 #define S_RH   "RH:"
 27 #define S_CRCT "CRC: True"
 28 #define S_CRCF "CRC: Wrong"
 29 #define S_Data "Data: "
 30 #define S_NotS "Sensor Not Connected"
 31  
 32 void Ack(void);
 33 void NoAck(void);
 34   
 35 void delay10us(void) //这个延时函数 要大于5US以上
 36 {
 37   _nop_(); _nop_(); _nop_(); 
 38   _nop_(); _nop_(); _nop_(); 
 39 }
 40   
 41 void delay1ms(unsigned int t)
 42 {
 43   unsigned int i;
 44   unsigned int j;
 45   for(j=t;j>0;j--)
 46    for(i=124;i>0;i--);  
 47 }
 48  
 49 void InitUART(void)
 50 {
 51     unsigned int iTmpBaud;
 52     unsigned long lTmpBaud;
 53     iTmpBaud = 0;
 54     //首先选定定时器2作为波特率发生器,16位定时器,自动装载
 55     SCON = 0x50;  //SM0 SM1 SM2 REN TB8 RB8 TI RI      //0   1   0   1   0   0   0  0 
 56     PCON = 0x00;  //PCON的地址是87H,这里SMOD =0
 57      
 58     T2CON = 0x30; //TF2 EXF2 RCLK TCLK EXEN2 TR2 C(/T2) CP(/RL2) //0 0 1 1 0 0 0 0 
 59     T2MOD = 0x00; // /   /   /   /       /   /   T2OE    DCEN   //0 0 0 0 0 0 0 0
 60  
 61     //fosc = 22.1184M,6T: 144,设置波特率
 62     //(RCAP2H,RCAP2L) = 65536- fosc/(n*Baud)。n:32(12T-mode),16:(6T-mode)
 63     lTmpBaud = FOSC/BAUD;
 64     lTmpBaud /= 32;                       //12T-mode
 65     iTmpBaud = lTmpBaud & 0xFFFF;      
 66     iTmpBaud = 65536 - iTmpBaud;
 67     RCAP2H = (iTmpBaud>>8) & 0x0FF;
 68     RCAP2L = iTmpBaud & 0x0FF;
 69  
 70     RI = 0;           //清除接收中断标志
 71     REN = 1;      //允许串行接收
 72     ES = 1;           //允许串行中断
 73     TR2 = 1;      //启动定时器1
 74  
 75     EA=1;//开总中断
 76 }  
 77  
 78 //串口发送
 79 void UARTSend(char UCHAR)
 80 {
 81    SBUF=UCHAR;
 82   while(TI==0);
 83   TI=0;
 84 }
 85  
 86 void UARTRead(void) interrupt 4
 87 {
 88   char temp;
 89   if(RI)
 90   {
 91     RI=0;
 92     temp = SBUF;
 93   }
 94 }
 95  
 96 //**********************************************
 97 //送起始位 sda=1->0
 98 void I2C_Start()
 99 {
100   SDA=1;
101   SCL=1;
102   delay10us();
103   SDA=0;
104   delay10us();
105   SCL=0; 
106 }
107 //************************************************
108 //送停止位 sda=0->1
109 void I2C_Stop()
110 {
111    SDA=0;
112    delay10us();
113    SCL=1;
114    delay10us();
115    SDA=1;
116 }
117 //************************************************
118 //主应答(包含ack:sda=0和no_ack:sda=0)
119 void Ack(void)
120 {  //设置SDA 口为输出
121    SDA=0;
122    SCL=0;
123    delay10us();
124    SCL=1;
125    delay10us(); 
126    SCL=0;
127    SDA=1;
128 }
129  
130 void NoAck(void)
131 {  //设置SDA 口为输出
132    SDA=1;  
133    SCL=0;
134    delay10us();
135    SCL=1;
136    delay10us();
137    SDA=1;
138    SCL=0;
139 }
140  
141 // 检测 SDA是否回ACK
142 bit Test_Ack()
143 {  //设置SDA 口为输入
144    bit ACK_Flag=0;
145    SCL=0;
146    SDA=1;    
147    delay10us();
148    SCL=1;
149    delay10us();
150    if(SDA==0)
151      ACK_Flag = 1;
152    else 
153      ACK_Flag = 0;
154    SCL=0;
155    return ACK_Flag;
156 }
157  
158 //*************************************************
159 //字节发送程序
160 //发送c(可以是数据也可是地址),送完后接收从应答
161 //不考虑从应答位
162 void SendData(unsigned char buffer)
163 {
164    unsigned char BitCnt=8;//一字节8位
165    //设置SDA 口为输出
166    do
167    {
168      SCL=0;
169       delay10us();
170       if((buffer&0x80)==0) //判断最高位是0还是1
171         SDA=0;
172       else
173         SDA=1;
174       SCL=1;
175       delay10us();
176       buffer=buffer<<1;//将buffer中的数据左移一位
177       BitCnt--;
178    }
179    while(BitCnt);
180    SCL=0;        
181 }
182 //**************************************************
183 //字节接收程序
184 //接收器件传来的数据,此程序应配合|主应答函数|i2c_ack_main()使用
185 //return: uchar型1字节
186 unsigned char ReceiveData()
187 {
188   unsigned char BitCnt=8,IIC_RX_Data=0;
189   unsigned char temp=0;
190   SDA=1;           //读入数据 设置SDA 口为输入
191   do
192   {
193      SCL=0;
194      delay10us();  
195      IIC_RX_Data=_crol_(IIC_RX_Data,1);   //数据左移一位
196      BitCnt--;   
197      SCL=1;
198      delay10us();
199      if(SDA==1)
200        IIC_RX_Data = IIC_RX_Data|0x01;  //低位置1
201      else
202        IIC_RX_Data = IIC_RX_Data&0x0fe; //低位清0        
203    }
204    while(BitCnt);
205    SCL=0;
206    return IIC_RX_Data;
207 }
208 //***************************************************
209 bit WriteNByte(unsigned char sla,unsigned char *s,unsigned char n)
210 {
211    unsigned char i;
212     
213    I2C_Start();  //启动I2C
214    SendData(sla);//发送器件地址
215    if(!Test_Ack())
216    {
217       WR_Flag = 1;
218       return(0);
219    }
220    for(i=0;i<n;i++)//写入8字节数据
221    {
222       SendData(*(s+i));
223       if(!Test_Ack())
224       {
225         WR_Flag = 1;
226         return(0);
227       }
228    }
229    I2C_Stop();
230    return(1);
231 }
232 bit ReadNByte(unsigned char Sal, unsigned char *p,unsigned char n)
233 {
234   unsigned char i;
235   I2C_Start();    // 启动I2C
236   SendData((Sal)| 0x01); //发送器件地址
237   if(!Test_Ack())
238   {
239       WR_Flag = 1;
240     return(0);
241   }
242   delay10us();  
243   delay10us();
244   delay10us(); // 延时时间必须大于30us 只要大于 30us 以上的值都可以 但是最好不要太长 ,测试时,试过25MS都OK! 
245          
246   for(i=0;i<n-1;i++)  //读取字节数据
247   {
248      *(p+i)=ReceiveData(); //读取数据
249      Ack(); 
250   }
251   *(p+n-1)=ReceiveData();        
252   NoAck();
253   I2C_Stop(); 
254   return(1);   
255 }
256 ///计算CRC校验码
257 unsigned int CRC16(unsigned char *ptr, unsigned char len)
258 {
259    unsigned int crc=0xffff;
260    unsigned char i;
261    while(len--)
262    {
263        crc ^=*ptr++;
264        for(i=0;i<8;i++)
265        {
266            if(crc & 0x1)
267            {
268               crc>>=1;
269               crc^=0xa001;
270            }
271            else
272            {
273               crc>>=1;
274            }
275        }
276    }
277    return crc;
278 }
279 ///检测CRC校验码是否正确
280 unsigned char CheckCRC(unsigned char *ptr,unsigned char len)
281 {
282   unsigned int crc;
283     crc=(unsigned int)CRC16(ptr,len-2);
284     if(ptr[len-1]==(crc>>8) && ptr[len-2]==(crc & 0x00ff))
285     {
286         return 0xff;
287     }
288     else
289     {
290        return 0x0;
291     }
292 }
293 void Waken(void)
294    {
295     I2C_Start();       // 启动I2C
296     SendData(IIC_Add); // 发送器件地址
297     Test_Ack();        // 唤醒指令时 传感器不会回ACK 但是第一定要发检测ACK的时钟 否则会出错
298     delay1ms(2);       // 至少延时1个Ms  说明书里,有个最大值 ,实际当中 你只要大于1MS
299     I2C_Stop();
300    }
301  
302 void UART_PutString(unsigned char *buf )
303 {
304     while(*buf)
305       UARTSend(*buf++);
306 } 
307  
308 void UART_PutStringAndNum(unsigned char *buf ,unsigned int num)
309 {
310     unsigned char a[3],i;
311     a[3] = '0'+num%10;
312     a[2] = '.';
313     a[1] = '0'+num/10%10;
314     a[0] = '0'+num/100%10;
315     while(*buf)
316       UARTSend(*buf++);
317     UARTSend(' ');
318      for(i=0;i<4;i++)
319     {
320         UARTSend(a[i]);
321     } 
322 }
323 void UART_PutStringAnd_Data(unsigned char *buf ,unsigned char *bufdata)
324   {
325     unsigned char a[2],i,j;
326     while(*buf)
327       UARTSend(*buf++);
328     UARTSend(' ');
329     for(i=0;i<8;i++)
330     {
331         a[0] = bufdata[i]/16; 
332         a[1] = bufdata[i]%16;
333         for(j=0;j<2;j++)
334         {
335           if(a[j]>9)
336           {
337             a[j] = (a[j]-10)+'A';
338           }
339           else
340           {
341             a[j] = a[j]+'0';
342           }
343           UARTSend(a[j]);
344         }
345         UARTSend(' ');
346     } 
347   }
348  
349 void UARTSend_Nbyte(void)
350       {
351        int Tmp; 
352        if(WR_Flag == 0)
353        {
354          if(CheckCRC(IIC_RX_Buffer,8))
355          {
356            String = S_Function;  // "Function: 03 04"
357            UART_PutString(String);
358           UARTSend(' ');
359            UARTSend(' ');
360  
361            String = S_RH;//"RH:"      
362            Tmp = IIC_RX_Buffer[2]*256+IIC_RX_Buffer[3];       
363            UART_PutStringAndNum(String,Tmp); 
364         
365            UARTSend(' ');
366            UARTSend(' ');
367            String = S_Temp; //"Temp:"
368                         
369            Tmp = IIC_RX_Buffer[4]*256+IIC_RX_Buffer[5];       
370            UART_PutStringAndNum(String,Tmp);
371             
372            UARTSend(' ');
373            UARTSend(' ');
374  
375            String = S_CRCT;//"CRC: True";
376            UART_PutString(String);
377  
378          }else
379          {
380             String = S_Data;//"Data: ";
381  
382             UART_PutStringAnd_Data(String,IIC_RX_Buffer);
383               UARTSend(' ');
384               UARTSend(' ');
385             String = S_CRCF;//"CRC: Wrong";
386               UART_PutString(String); 
387          }
388         }
389         else
390         {
391            String = S_NotS;//"Sensor Not Connected";
392           UART_PutString(String);
393         }       
394        UARTSend(0x0A);            
395  
396        }  
397 void Clear_Data (void)
398      {
399         int i;
400         for(i=0;i<IIC_RX_Length;i++)
401          {
402          IIC_RX_Buffer[i] = 0x00;
403          }//接收数据清零
404       }
405  
406 void main(void)
407 {
408   SCL = 1;
409   SDA = 1; //上电时保证两总线为高
410   InitUART();
411   Clear_Data();
412   while(1)
413   {
414     Clear_Data(); // 清除收到数据
415     WR_Flag = 0;
416     Waken();      // 唤醒传感器
417     //发送读指令
418     WriteNByte(IIC_Add,IIC_TX_Buffer,3); 
419     //发送读取或写数据命令后,至少等待2MS(给探头返回数据作时间准备)
420     delay1ms(2);    
421     //读返回数据
422     ReadNByte(IIC_Add,IIC_RX_Buffer,8);
423  
424     SCL = 1; SDA = 1;  //确认释放总线
425       //通过串口向上发送传感器数据
426     UARTSend_Nbyte();
427  
428     delay1ms(2000);   //延时 2S    (两次读取间隔至少2S)
429   }
430 }

实物图

引脚图

接线图

效果图

编译图

原文地址:https://www.cnblogs.com/kwkk978113/p/14152838.html