功能介紹:
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://www.uj5u.com/qita/227990.html
標籤:其他
上一篇:C#實作聊天功能
