WHT20无线温湿度传感器 STM8S单片机

 想做一个能够远程检测温湿度的东西,这样家里放一个,外面放一个,早上一起来就能看到实时的温湿度,岂不美滋滋。

 最初想法是单独买温湿度的传感器,像DHT11那样,然后在买一个无线模块像NRF24L01,然后再配个微控制器啥的,后来在淘宝搜着搜着就发现了WHT20这款神器,他本身就有无线功能,而且他的传感器是SHT20,精度更高。然后这样我就只要配个接收的微控制器,选来选去,觉得51用腻了,STM32有点大材小用了,Arduino  Emmmm......不想用,就用了STM8S这么一个从来没用过的的微控制器。

 先说下WHT20和他配套的接收器WSR。

一、WHT20



这是他官方介绍.(我只是不想打这么多字)

上面就有他的引脚,它可以通过串口在线设置,也可以通过WSR进行设置,他的VCC只能接3.3V左右的电压,实际测试,接5V虽然不会坏,但是发的都是乱码。

1.通过串口设置

通过串口设置时候,要把他的SET脚拉低,然后通过串口给他发送指令。(十六进制发送)


CC是开始标志;Time就是他的采集周期,可以设置1-65536s(占两个字节);NETID是他的网络号,只有WHT20和WSR的网络号相同时候才能通信,范围0-65535(两个字节);功率是设置他的发射功率(一个字节);波特率就是串口波特率(一个字节);Chose设置1时,他无线发射的同时也会通过串口发送,0就只无线发射(一个字节);Channel就是通信频道,有128个频道(一个字节);SUM是前面所有字节加起来,取低八位(一个字节),这校验和正确的时候,传感器才会返回值,不正确也能设置成功,不过不会返回....不知道算不算它的一个BUG;FF结束标志。


功率的对应表。


波特率对应表。

2.无线设置

短暂拉低KEY脚后拉高,此时就可以等待WSR的设置指令,此时传感器参数会恢复到默认状态NETID=0000,power=12dBm,channel=0x64.然后WSR就发射设置指令,按照如下格式。


只有指定的传感器ID才能接受设置参数,FFFFFF的话,会设置所有处于设置状态的传感器。

传感器设置成功后悔将参数保存到EEPROM中,然后发射返回值。


二、WSR


CS是片选,接低电平工作。SET是设置,拉低可通过串口对他进行设置。

1.串口设置自身参数。

拉低SET脚后,串口发送0XAA+0X5A+模块ID+NETID+0X00+POWER+0X00+波特率+0X00+Channel+0X00

+0X00+0X12+0X00+SUM

参数意义同WHT20。

2.设置传感器参数

WSR的SET拉低,通过串口发送AA5E指令,就可以设置处于设置状态的WHT20了


参数意义同WHT20,设置成功后就会返回AA5F指令



再就是他们之间的通讯协议了


这款传感器还是不错的,功耗真的挺低的,实测,12dBm的功率,采集周期7S,我用的锂电池,平均电流大概在1.6mA左右,也就是一个2000mah的锂电池,能用大概40多天。


STM8S

这个单片机不能用keil开发,只能用IAR和官方的STVD,网上的程序也是挺少的,开发它我也废了一番功夫。

我要用它的串口然后再用它驱动12864,我用的那一款引脚很少,所以12864我就用了SPI驱动方式。

说到底只是款单片机,看下时钟,看下各种片内外设寄存器就能用了呗。这个淘宝买的系统板,4块钱一个,真是便宜啊。。


官方的资料也是少之又少,他这板子用的是内部RC振荡电路提供时钟源,官方介绍说他因为出产,环境啥的不同,导致有差异。。。。就直接说不太准就行了呗.......,而且他是啥三级流水线,这个三级流水线意思就是呢...取指令,指令解码,指令执行交给了三个人去做,这样效率会快很多,但是
这也就造成一个问题,一条汇编指令,他的周期我不知道是多少了....

要想延时准还得用汇编........

volatile u8 fac_us=0; 


void delay_init(u8 clk)
{
 if(clk>16)fac_us=(16-4)/4;//24Mhz时,stm8大概19个周期为1us
 else if(clk>4)fac_us=(clk-4)/4; 
 else fac_us=1;
}


void delay_us(u16 nus)
{
__asm(
"PUSH A          \n"    //压栈 1T
"DELAY_XUS:      \n"   
"LD A,fac_us     \n"    //倍延加载到累加器A 1T
"DELAY_US_1:     \n"  
"NOP             \n"    //1T
"DEC A           \n"    //1T
"JRNE DELAY_US_1 \n"    //!=0 跳转(2T)到DELAY_US_1执行, =0 不跳转(1T).
"NOP             \n"    //1T
"DECW X          \n"    //1T
"JRNE DELAY_XUS  \n"    //!=0 跳转(2T)到DELAY_XUS 执行, =0 不跳转(1T).
"POP A           \n"    //出栈 1T
);
}

STM8S 通过SPI驱动LCD12864

void SPI_12864_Init(void)
{
   SPI_Init(SPI_FIRSTBIT_MSB, SPI_BAUDRATEPRESCALER_2, SPI_MODE_MASTER,\
            SPI_CLOCKPOLARITY_HIGH, SPI_CLOCKPHASE_2EDGE, \
            SPI_DATADIRECTION_2LINES_FULLDUPLEX, SPI_NSS_SOFT, 0x00);
   SPI_Cmd(ENABLE);
   GPIO_Init(GPIOC,GPIO_PIN_4,\
             GPIO_MODE_OUT_PP_HIGH_FAST );//定义LED的管脚的模式
   GPIO_WriteHigh(GPIOC, GPIO_PIN_4);
		
}
void LCD_wr(u8 lcd_com,u8 lcd_data)                                         //写入LCD数据或命令
{
        u8 lcd_data_msb,lcd_data_lsb;
        lcd_data_msb=0xf0&lcd_data;
        lcd_data_lsb=(0x0f&lcd_data)<<4;
        if(lcd_com==0)                                        //写命令
        {
            while (SPI_GetFlagStatus( SPI_FLAG_TXE) == RESET);        //等待 SPI 发送缓冲空
            SPI_SendData(0xf8);                        // SPI 发送数据--命令指令-- 
        }
        if(lcd_com==1)                                        //写数据
        {
            while (SPI_GetFlagStatus( SPI_FLAG_TXE) == RESET);               //等待 SPI1 发送缓冲空
            SPI_SendData(0xfa);                    //SPI1 发送数据--数据指令--
        }
        delay_ms(1);
        while(SPI_GetFlagStatus( SPI_FLAG_TXE) == RESET);                //等待 SPI1 接收数据完毕
        SPI_SendData(lcd_data_msb);                   //SPI1 发送高4位数据
        delay_ms(1);
        while(SPI_GetFlagStatus( SPI_FLAG_TXE) == RESET);                //Wait for SPI1 Tx buffer empty
        SPI_SendData(lcd_data_lsb);            // SPI1 发送低4位数据
        delay_ms(1);
}        
void initlcd(void)                          //LCD初始化
{
  LCD_wr(0,0x30);                  //30---基本指令动作 
  delay_ms (4);
  LCD_wr(0,0x01);                  //清屏,地址指针指向00H
  delay_ms (3);
  LCD_wr(0,0x06);                  //光标的移动方向
  delay_ms (1);
  LCD_wr(0,0x0c);                  //开显示,关游标
  delay_ms (1);        
}
//LCD显示字符串
//X Y起始坐标
//*ptr 字符串地址  dat 字符串长度
//返回值 无
void LCD_showstring(u8 X,u8 Y,u8 *ptr,u8 dat)                      
{
  u8 i;
  switch(X)         //判断第几行
  {
    case 0:Y|=0x80;break;
    case 1:Y|=0x90;break;
    case 2:Y|=0x88;break;
    case 3:Y|=0x98;break;
    default:break;
  }
  LCD_wr(0,Y);       //发送起始地址
  for (i=0;i<dat;i++)
  {
    LCD_wr(1,*ptr++);
  }
}
//LCD显示数字(包括负数)
//X,Y 数字显示起始地址
void LCD_shownum(u8 X,u8 Y,char num)  
{
  switch(X)        //判断第几行
  {
    case 0:Y|=0x80;break;
    case 1:Y|=0x90;break;
    case 2:Y|=0x88;break;
    case 3:Y|=0x98;break;
    default:break;
  }
   LCD_wr(0,Y);
   if(num>=128)           //大于128代表负数
   {
    LCD_wr(1,0x2D);       //显示‘-’
    num=num&0x7f;         //最高位置零
    LCD_wr(1,num/10+0x30);//取十位
    LCD_wr(1,num%10+0x30);//取个位
   }
   else if(num<128)
   {
    LCD_wr(1,(num)/10+0x30);
    LCD_wr(1,(num)%10+0x30);
   }
}

串口相关程序

void Uart_Init(void)
{
    UART1_DeInit();
    UART1_Init((u32)9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, \
    UART1_PARITY_NO , UART1_SYNCMODE_CLOCK_DISABLE , UART1_MODE_TXRX_ENABLE);
    UART1_ITConfig(UART1_IT_RXNE_OR,ENABLE  );
    UART1_Cmd(ENABLE );
  
}

void UART1_SendByte(u8 data)
{
    UART1_SendData8((unsigned char)data);
  /* Loop until the end of transmission */
  while (UART1_GetFlagStatus(UART1_FLAG_TXE) == RESET);
}

void UART1_SendString(u8* Data,u16 len)
{
  u16 i=0;
  for(;i<len;i++)
    UART1_SendByte(Data[i]);
  
}

u8 UART1_ReceiveByte(void)
{
     u8 USART1_RX_BUF; 
     while (UART1_GetFlagStatus(UART1_FLAG_RXNE) == RESET);
     USART1_RX_BUF=UART1_ReceiveData8();
     return  USART1_RX_BUF;
    
}

 void CLR_BUF()         //清空串口接收缓存              
{
  point=0;
  memset( RxBuffer,0,20);      
}

#pragma vector=20
__interrupt void UART1_RX_IRQHandler(void)
{ 
   u8 Res;
   static u8 start;
   //LCD_display(0,0,"hello1",8);
    if(UART1_GetITStatus(UART1_IT_RXNE )!= RESET)  /*接收中断(接收到的数据必须是0x0d 0x0a结尾)*/
    {
	Res =UART1_ReceiveData8();/*(USART1->DR);读取接收到的数据,当读完数据后自动取消RXNE的中断标志位*/
 	if(Res==0xAA) {start=1;} //判断数据是否开始
        if(Res==0x5B) {cmd_responce=1;}  //判断是否是命令
        if(Res==0xFF) {start=0;usart_flag=1;}  //判断是否结束
        if(start) RxBuffer[point++]=Res;    //读取命令OR数据
    }
  
  
}

WSR相关函数

void wsr_Init(void)
{
   GPIO_Init(GPIOA,GPIO_PIN_1,\
             GPIO_MODE_OUT_PP_HIGH_FAST );//SET脚接A1
      GPIO_Init(GPIOA,GPIO_PIN_2,\
             GPIO_MODE_OUT_PP_HIGH_FAST );//CS脚接A2
   GPIO_WriteLow(GPIOA, GPIO_PIN_2);
   GPIO_WriteHigh(GPIOA, GPIO_PIN_1);
}
//WSR设置函数
//NETID:网络号 power:功率 channel:频道 baud:波特率
//返回参数:0:设置不成功
//          1:设置成功
u8 wsr_set(u8 NETID,u8 power,u8 channel,u8 baud)
{ 
  u8 i;
  u8 cmd[18]={0xAA,0X5A,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X04,0X00,0X64,0X00,0X00,0X00,0X12,0X00,0X00};//命令数组
  cmd[5]=NETID;
  cmd[7]=power;
  cmd[9]=baud;
  cmd[11]=channel;
  for(i=0;i<17;i++)
  cmd[17]=cmd[17]+cmd[i];   //添加校验位
  GPIO_WriteLow(GPIOA, GPIO_PIN_1);  //SET L
  delay_ms(1);
  UART1_SendString(cmd,18); //发送命令
  //delay_ms(1);
  while(!cmd_responce);   //等待命令回复
  cmd_responce=0;
  GPIO_WriteHigh(GPIOA, GPIO_PIN_1); //SET H
  delay_ms(3);
  if(RxBuffer[5]==NETID&&RxBuffer[7]==power&&RxBuffer[9]==baud&&RxBuffer[11]==channel)   //判断是否设置成功
  {
    CLR_BUF();
    return 1;
  }
  CLR_BUF();
  return 0;  
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不会飞的瘦子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值