STM8S003F3P6采集DS18B20数码管显示 串口通讯

2022-07-27,,,,

功能介绍:

STM8S003F3P6使用单总线方式和DS18B20建立简单的通讯、DS18B20反馈温度值,数码管显示温度值无小数,利用串口命令可以设置数码管亮灭,温度值上传周期等等。具体以协议为准。程序源码在一个资源里面,下载需要积分,没有积分的可以私信我。https://download.csdn.net/download/L_e_c/13187959

硬件设计:

如下图,一个单片机预留烧录口,两位共阴数码管,数码管在原理图中省略了,一路DS18B20接上拉之后到芯片引脚。一路UART可直接通过USB转TTL模块连接电脑调试。

软件设计:

1)主程序设计

初始化芯片内部flash(给串口命令保存参数用,)初始化IO口(数码管段选及位选),DS18B20初始化,定时器(定时1ms,给主程序做时基用),初始化串口,打开中断。大循环里以Auto_Flag变量分三个方式,程序看明白了其实没有太大的区别;然后就是串口接收到协议相应的命令,给一些标志位置位,然后在大循环里应答,不占用中断时间;system1ms是1ms的时基,显示刷新周期是2*4ms;再往后就是500ms采集一次温度值然后给显示数组赋值(在这里处理的正负温度值),数码管的亮灭也是在500ms的时基里处理的;再下面的Usart1_Rev_flag变量是确定直接返回温度值还是周期返回温度值;后面几乎相同,废话不说,直接贴程序。

int main(void)
{
  u8 state=0;
  u8 cclen=0;
//   u16 Cnt_500ms=0;
   u16 Cnt_2S=0;
   u8 SendCnt_xS=0;
   u8 Cnt_10ms=0;
   
  /*设置内部高速时钟16M为主时钟*/ 
   CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
   FLASH_Initializes();
   
  /*!<Set High speed internal clock */
   delay_init(16);
   
   LED_Init();
   Init_DS18B20();
   Tim1_Init();
   SetLedOFF(); 
    GPIO_Init(GPIOD, GPIO_PIN_5, GPIO_MODE_OUT_OD_LOW_FAST);         
    GPIO_Init(GPIOD, GPIO_PIN_6, GPIO_MODE_IN_PU_NO_IT); 
   Uart_Init();
   
  __enable_interrupt(); 
  delay_ms(100);
  Data_Init();
//  UART1_SendString("Serial Communication ---STM8 Development Board of FengChi Electron ",\
//             sizeof("Serial Communication ---STM8 Development Board of FengChi Electron"));
  Led_Temp[0]=11;
  Led_Temp[1]=11;
  if(Auto_Flag==0){
    Usart1_Rev_Cot_flag=0;
  }
  else if(Auto_Flag==1)
  {
    Usart1_Rev_Cot_flag=1;
  }
  else if(Auto_Flag==2)
  {
    Usart1_Rev_Cot_flag=1;
    SendTime_Num=1;
  }
  
  
  while (1)
  { 
    if(Auto_Flag==0){
        if (SendTime_Flag==1)
        {
          SendTime_Flag=0;
          UART1_SendString("ok\r\n",4);
        }
        if(SendAuto_Flag==1){
          SendAuto_Flag=0;
          UART1_SendString("ok\r\n",4);
        }
        if(system1ms==1)
        {
          system1ms=0;
          if(++Cnt_10ms>=2)
          {
            Cnt_10ms=0;
            switch (state)
            {
              case 0 :{
                state = 1;
                Assembly_2(~0X00);
                Assembly_8(~seg7[Led_Temp[0]]);
                Assembly_2(~0X01);
              }break;
              case 1 :{
                state = 2;
                Assembly_2(~0X00);
                Assembly_8(~seg7[Led_Temp[1]]);
                Assembly_2(~0X02);
              }break;
              case 2 :{
                state = 3;
                Assembly_2(~0X00);
                Assembly_8(~seg7[Led_Temp[0]]);
                Assembly_2(~0X01);
                Temptrue=Read_DS18B20();
              }break;
              case 3 :{
                state = 0;
                Assembly_2(~0X00);
                Assembly_8(~seg7[Led_Temp[1]]);
                Assembly_2(~0X02);
              }break;
              default: state = 0;
              break;
            }
          } 
          if(++Cnt_2S>=500)
          {
              Cnt_2S=0;
              if(Temptrue>=0){
                cclen=sprintf(Send_Server,"Temptrue=%02d.%01d;\r\n",Temptrue/10,Temptrue%10);
                Led_Temp[0]=Temptrue/100+12;  
                Led_Temp[1]=Temptrue/10%10;
              }
              else
              {
                cclen=sprintf(Send_Server,"Temptrue=-%02d.%01d;\r\n",(0-Temptrue)/10,(0-Temptrue)%10);
                if((0-Temptrue)>199) Led_Temp[0]=(0-Temptrue)/100+12;  
                else if((0-Temptrue)>99)  Led_Temp[0]=11+14;
                else Led_Temp[0]=11+13;
                                    Led_Temp[1]=(0-Temptrue)/10%10+12;
              }
              if(Usart1_Rev_Cot_flag==0)
              {
                Led_Temp[0]=11;
                Led_Temp[1]=11;
                Temptrue=Read_DS18B20();
              }
              
          }
        }  
        if(Usart1_Rev_flag==1){
          Usart1_Rev_flag=0;
          UART1_SendString(Send_Server,cclen);
        }
        else {
          if(system1S==1){
            system1S=0;
            if(SendTime_Num!=0){
              if(++SendCnt_xS>=SendTime_Num){
                SendCnt_xS=0;
                UART1_SendString(Send_Server,cclen);
              }
            }
          }
        }
      
    }else if(Auto_Flag==1){
      if (SendTime_Flag==1)
        {
          SendTime_Flag=0;
          UART1_SendString("ok\r\n",4);
        }
        if(SendAuto_Flag==1){
          SendAuto_Flag=0;
          UART1_SendString("ok\r\n",4);
        }
        if(system1ms==1)
        {
          system1ms=0;
          if(++Cnt_10ms>=2)
          {
            Cnt_10ms=0;
            switch (state)
            {
              case 0 :{
                state = 1;
                Assembly_2(~0X00);
                Assembly_8(~seg7[Led_Temp[0]]);
                Assembly_2(~0X01);
              }break;
              case 1 :{
                state = 2;
                Assembly_2(~0X00);
                Assembly_8(~seg7[Led_Temp[1]]);
                Assembly_2(~0X02);
              }break;
              case 2 :{
                state = 3;
                Assembly_2(~0X00);
                Assembly_8(~seg7[Led_Temp[0]]);
                Assembly_2(~0X01);
                Temptrue=Read_DS18B20();
              }break;
              case 3 :{
                state = 0;
                Assembly_2(~0X00);
                Assembly_8(~seg7[Led_Temp[1]]);
                Assembly_2(~0X02);
              }break;
              default: state = 0;
              break;
            }
          } 
          if(++Cnt_2S>=500)
          {
              Cnt_2S=0;
              if(Temptrue>=0){
                cclen=sprintf(Send_Server,"Temptrue=%02d.%01d;\r\n",Temptrue/10,Temptrue%10);
                Led_Temp[0]=Temptrue/100+12;  
                Led_Temp[1]=Temptrue/10%10;
              }
              else
              {
                cclen=sprintf(Send_Server,"Temptrue=-%02d.%01d;\r\n",(0-Temptrue)/10,(0-Temptrue)%10);
                if((0-Temptrue)>199) Led_Temp[0]=(0-Temptrue)/100+12;  
                else if((0-Temptrue)>99)  Led_Temp[0]=11+14;
                else Led_Temp[0]=11+13;
                                    Led_Temp[1]=(0-Temptrue)/10%10+12;
              }
              if(Usart1_Rev_Cot_flag==0)
              {
                Led_Temp[0]=11;
                Led_Temp[1]=11;
                Temptrue=Read_DS18B20();
              }
              
          }
        }  
        if(Usart1_Rev_flag==1){
          Usart1_Rev_flag=0;
          UART1_SendString(Send_Server,cclen);
        }
        else {
          if(system1S==1){
            system1S=0;
            if(SendTime_Num!=0){
              if(++SendCnt_xS>=SendTime_Num){
                SendCnt_xS=0;
                UART1_SendString(Send_Server,cclen);
              }
            }
          }
        }
      }
    else if(Auto_Flag==2){
      if (SendTime_Flag==1)
        {
          SendTime_Flag=0;
          UART1_SendString("ok\r\n",4);
        }
        if(SendAuto_Flag==1){
          SendAuto_Flag=0;
          UART1_SendString("ok\r\n",4);
        }
        if(system1ms==1)
        {
          system1ms=0;
          if(++Cnt_10ms>=2)
          {
            Cnt_10ms=0;
            switch (state)
            {
              case 0 :{
                state = 1;
                Assembly_2(~0X00);
                Assembly_8(~seg7[Led_Temp[0]]);
                Assembly_2(~0X01);
              }break;
              case 1 :{
                state = 2;
                Assembly_2(~0X00);
                Assembly_8(~seg7[Led_Temp[1]]);
                Assembly_2(~0X02);
              }break;
              case 2 :{
                state = 3;
                Assembly_2(~0X00);
                Assembly_8(~seg7[Led_Temp[0]]);
                Assembly_2(~0X01);
                Temptrue=Read_DS18B20();
              }break;
              case 3 :{
                state = 0;
                Assembly_2(~0X00);
                Assembly_8(~seg7[Led_Temp[1]]);
                Assembly_2(~0X02);
              }break;
              default: state = 0;
              break;
            }
          } 
          if(++Cnt_2S>=500)
          {
              Cnt_2S=0;
              if(Temptrue>=0){
                cclen=sprintf(Send_Server,"Temptrue=%02d.%01d;\r\n",Temptrue/10,Temptrue%10);
                Led_Temp[0]=Temptrue/100+12;  
                Led_Temp[1]=Temptrue/10%10;
              }
              else
              {
                cclen=sprintf(Send_Server,"Temptrue=-%02d.%01d;\r\n",(0-Temptrue)/10,(0-Temptrue)%10);
                if((0-Temptrue)>199) Led_Temp[0]=(0-Temptrue)/100+12;  
                else if((0-Temptrue)>99)  Led_Temp[0]=11+14;
                else Led_Temp[0]=11+13;
                                    Led_Temp[1]=(0-Temptrue)/10%10+12;
              }
              if(Usart1_Rev_Cot_flag==0)
              {
                Led_Temp[0]=11;
                Led_Temp[1]=11;
                Temptrue=Read_DS18B20();
              }
              
          }
        }  
        if(Usart1_Rev_flag==1){
          Usart1_Rev_flag=0;
          UART1_SendString(Send_Server,cclen);
        }
        else {
          if(system1S==1){
            system1S=0;
            if(SendTime_Num!=0){
              if(++SendCnt_xS>=SendTime_Num){
                SendCnt_xS=0;
                UART1_SendString(Send_Server,cclen);
              }
            }
          }
        }
      } 
    
  }
}

2)DS18B20.c

编写该程序只需要记住一点,一定要和时序对应起来;首先要留意延时函数,往往延时函数是导致和18B20通讯不成功的主要因素。其他就没有太多要说的了,看源码。

#include "ds18b20.h"

u16 temp=0;
s16 Temptrue=0;

/* Private functions ---------------------------------------------------------*/
/* Public functions ----------------------------------------------------------*/
void Alarm_for_No_DS18B20(void)
{
    //单总线上没有发现DS18B20则报警,该动作据具体应用具体处理
}
//---------------------------------------------------------------------
unsigned char DS18B20_Start(void) //复位ds18b20芯片
{
    unsigned char i,succ=0xff;
    DS18B20_PIN_SET_OUT(); //置为输出口
    DS18B20_WR0();          //总线产生下降沿,初始化开始
    // for(i=0; i<30; i++)delay_us(25); //总线保持低电平在480 - 960微秒之间  ;i<20;(25us)
    delay_us(500);
    DS18B20_WR1();         //总线拉高
    DS18B20_PIN_SET_IN();  //置为输入,主机释放总线,准备接收DS18B20的应答脉冲
    i=0;
    while(R_DS18B20())         //等待DS18B20发出应答脉冲
    {
        delay_us(5);          //5
        if(++i>12)            //DS18B20检测到总线上升沿后等待15-60us
        {
            succ=0x00;           //如果等待大于约60us,报告复位失败
            break;
        }
    }
    i=0;
    while(!R_DS18B20())       //DS18B20发出存在脉冲,持续60-240us
    {
        delay_us(5);         //5
        if(++i>48)            //如果等带大于约240us,报告复位失败
        {
            succ=0x00;
            break;
        }
    }
    delay_us(20);
    return succ;
}
//---------------------------------------------------------------------
void DS18B20_SendU8(unsigned char d8)//向DS18B20写一字节函数
{
    unsigned char i;
    DS18B20_PIN_SET_OUT();   //置为输出口
    for(i=0; i<8; i++)
    {
        DS18B20_WR0();       //总线拉低,启动“写时间片”
        delay_us(2);            //大于1微妙
        if(d8&0x01)DS18B20_WR1();
        delay_us (32);      //延时至少60微秒,使写入有效
        delay_us (30);
        DS18B20_WR1();       //总线拉高,释放总线,准备启动下一个“写时间片”
        d8>>=1;
        delay_us (1);
    }
    DS18B20_PIN_SET_IN();   //主机释放总线
}
//---------------------------------------------------------------------
unsigned char DS18B20_ReadU8(void)//从DS18B20读1个字节函数
{
    unsigned char i,d8;
    for(i=0; i<8; i++)
    {
        d8>>=1;
        DS18B20_PIN_SET_OUT();//置为输出口
        DS18B20_WR0();        //总线拉低,启动读“时间片”
        delay_us(2);         //大于1微妙
        DS18B20_WR1();        //主机释放总线,接下来(2~15)us内读有效
        DS18B20_PIN_SET_IN(); //引脚设定为输入口,准备读取
        delay_us(2);         //延时2个us后进行读


        if(R_DS18B20())d8|=0x80;//从总线拉低时算起,约15微秒内读取总线数据
        delay_us(32);       //60us后读完成
        delay_us(30);
        DS18B20_WR1();       //总线拉高,主机释放总线,准备启动下一个“写时间片”
    }
    DS18B20_PIN_SET_IN();    //主机释放总线
    return(d8);
}
//------------------------------------------------------------------------------------
void Init_DS18B20(void)           //初始化DS18B20
{
    unsigned char i;
    i=DS18B20_Start();             //复位
    if(!i)                          //单总线上没有发现DS18B20则报警
    {
        Alarm_for_No_DS18B20();
        return;
    }
    DS18B20_SendU8 (SKIP_ROM);  //跳过rom匹配
    DS18B20_SendU8 (WRITE_RAM); //设置写模式
    DS18B20_SendU8 (0x64);        //设置温度上限100摄氏度
    DS18B20_SendU8 (0x8a);        //设置温度下线-10摄氏度
    DS18B20_SendU8 (0x7f);        //12bit(默认)
}


//--------------------------------------------------------------------------------------

unsigned char tl;
    unsigned int  th;
unsigned int Read_DS18B20(void)  //读取并计算要输出的温度
{
    unsigned char i;
    
    i=DS18B20_Start();           //复位
    if(!i)                        //单总线上没有发现DS18B20则报警
    {
        Alarm_for_No_DS18B20();
        return 0;
    }
    // delay_ms(1);
    DS18B20_SendU8(SKIP_ROM);     //发跳过序列号检测命令
    DS18B20_SendU8(CONVERT_TEM); //命令Ds18b20开始转换温度
    i=0;
    // delay_ms(1);
    while(!R_DS18B20())       //当温度转换正在进行时,主机读总线将收到0,转换结束为1
    {
        delay_ms(2);
        if(++i>250) break;              //至多转换时间为750ms
    }
    DS18B20_Start();                 //初始化
    // delay_ms(1);
    DS18B20_SendU8(SKIP_ROM);    //发跳过序列号检测命令
    DS18B20_SendU8(READ_RAM);  //发读取温度数据命令
    tl=DS18B20_ReadU8();           //先读低8位温度数据
    th=DS18B20_ReadU8()<<8;        //再读高8位温度数据
    if((th&0xf000)==0xf000)   
      return -((0-(th|tl))*10>>4);
    else 
      return (th|tl)*10>>4;              //温度放大了10倍,*0.0625=1/16=>>4
}


3)其他

内部Flash操作和UART操作,就是一些配置,熟悉库操作就可以,串口接收中断可以看一下处理方式(状态机),后续可以考虑使用帧中断,之后在其他博客会分享。

4)协议、硬件及调试效果

总结:

博客就只是分享了原理图和程序,一些注释也不全。第一个分享,难免有不对之处,欢迎指正交流,谢谢。

本文地址:https://blog.csdn.net/L_e_c/article/details/110124651

《STM8S003F3P6采集DS18B20数码管显示 串口通讯.doc》

下载本文的Word格式文档,以方便收藏与打印。