功能介绍:

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