久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费
標題:
單片機溫度監控系統 電機轉動 匯編與C語言源程序注釋很詳細 Proteus仿真圖
[打印本頁]
作者:
cjj111
時間:
2021-6-10 22:06
標題:
單片機溫度監控系統 電機轉動 匯編與C語言源程序注釋很詳細 Proteus仿真圖
一個溫度監控系統
51hei.png
(15.4 KB, 下載次數: 49)
下載附件
2021-6-11 00:18 上傳
單片機源程序如下:
#include<reg51.h> //預處理命令,定義SFR的頭
#include <math.h>
#define uchar unsigned char //定義縮寫字符uchar
#define uint unsigned int //定義縮寫字符uint
#define lcd_data P0 //定義LCD1602接口 P0
sbit DQ =P1^7; //將DQ位定義為P1.7引腳
sbit lcd_RS=P2^0; //將RS位定義為P2.0引腳
sbit lcd_RW=P2^1; //將RW位定義為P2.1引腳
sbit lcd_EN=P2^2; //將EN位定義為P2.2引腳
sbit PWM=P3^7; //將PWM定義為P3.7引腳
sbit D=P3^6; //將d定義為P3.6引腳,轉向選擇位
uchar t[2],speed,temperature; //用來存放溫度值,測溫程序就是通過這個數組與主函數通信的
uchar DS18B20_is_ok;
uchar TempBuffer1[12]={0x20,0x20,0x20,0x20,0xdf,0x43,'\0'};
uchar tab[16]={0x20,0x20,0x20,0x54,0x20,0x4d,0x6f,0x6e,0x69,0x74,0x6f,0x72,'\0'};
//顯示"T Monitor"
/**********lcd顯示子程序************/
void delay_20ms(void) /*延時20ms函數*/
{
uchar i,temp; //聲明變量i,temp
for(i = 20;i > 0;i--) //循環
{
temp = 248; //給temp賦值248
while(--temp); //temp減1是否等于0,否則繼續執行該行
temp = 248; //給temp賦值248
while(--temp); //temp減1是否等于0,否則繼續執行該行
}
}
void delay_38us(void) /*延時38us函數*/
{ uchar temp; //聲明變量temp
temp = 18; //給temp賦值
while(--temp); //temp減1是否等于0,否則繼續執行該行
}
void delay_1520us(void) /*延時1520us函數*/
{ uchar i,temp; //聲明變量i,temp
for(i = 3;i > 0;i--) //循環
{
temp = 252; //給temp賦值
while(--temp); //temp減1是否等于0,否則繼續執行該行
}
}
uchar lcd_rd_status( ) /*讀取lcd1602的狀態,主要用于判斷忙*/
{
uchar tmp_sts; //聲明變量tmp_sts
lcd_data = 0xff; //初始化P3口
lcd_RW = 1; //RW =1 讀
lcd_RS = 0; //RS =0 命令,合起來表示讀命令(狀態)
lcd_EN = 1; //EN=1,打開EN,LCD1602開始輸出命令數據,100nS之后命令數據有效
tmp_sts = lcd_data; //讀取命令到tmp_sts
lcd_EN = 0; //關掉LCD1602
lcd_RW = 0; //把LCD1602設置成寫
return tmp_sts; //函數返回值tmp_sts
}
void lcd_wr_com(uchar command ) /*寫一個命令到LCD1602*/
{
while(0x80&lcd_rd_status()); //寫之前先判斷LCD1602是否忙,看讀出的命令的最高位是否為1,為1表示忙,繼續讀,直到不忙
lcd_RW = 0;
lcd_RS = 0; //RW=0,RS=0 寫命令
lcd_data = command; //把需要寫的命令寫到數據線上
lcd_EN = 1;
lcd_EN = 0; //EN輸出高電平脈沖,命令寫入
}
void lcd_wr_data(uchar sjdata ) /*寫一個顯示數據到lcd1602*/
{
while(0x80&lcd_rd_status()); //寫之前先判斷lcd1602是否忙,看讀出的命令的最高位是否為1,為1表示忙,繼續讀,直到不忙
lcd_RW = 0;
lcd_RS = 1; //RW=0,RS=1 寫顯示數據
lcd_data = sjdata ; //把需要寫的顯示數據寫到數據線上
lcd_EN = 1;
lcd_EN = 0; //EN輸出高電平脈沖,命令寫入
lcd_RS = 0;
}
void Init_lcd(void) /*初始化lcd1602*/
{
delay_20ms(); //調用延時
lcd_wr_com(0x38); //設置16*2格式,5*8點陣,8位數據接口
delay_38us(); //調用延時
lcd_wr_com(0x0c); //開顯示,不顯示光標
delay_38us(); //調用延時
lcd_wr_com(0x01); //清屏
delay_1520us(); //調用延時
lcd_wr_com(0x06); //顯示一個數據后光標自動+1
}
void GotoXY(uchar x, uchar y) //設定位置,x為行,y為列
{
if(y==0) //如果y=0,則顯示位置為第一行
lcd_wr_com(0x80|x);
if(y==1)
lcd_wr_com(0xc0|x); //如果y=1,則顯示位置為第二行
}
void Print(uchar *str) //顯示字符串函數
{
while(*str!='\0') //判斷字符串是否顯示完
{
lcd_wr_data(*str); //寫數據
str++;
}
}
void LCD_Print(uchar x, uchar y, uchar *str)//x為行值,y為列值,str是要顯示的字符串
{
GotoXY(x,y); //設定顯示位置
Print(str); //顯示字符串
}
/*****************系統顯示子函數*****************/
void covert1() //溫度轉化程序
{
uchar x=0x00; //變量初始化
if(t[1]>0x07) //判斷正負溫度
{
TempBuffer1[0]=0x2d; //0x2d為"-"的ASCII碼
t[1]=~t[1]; //負數的補碼
t[0]=~t[0]; //換算成絕對值
x=t[0]+1; //加1
t[0]=x; //把x的值送入t[0]
if(x>255) //如果x大于255
t[1]++; //t[1]加1
}
else
TempBuffer1[0]=0x2b; //0xfe為變"+"的ASCII碼
t[1]<<=4; //將高字節左移4位
t[1]=t[1]&0x70; //取出高字節的3個有效數字位
x=t[0]; //將t[0]暫存到X,因為取小數部分還要用到它
x>>=4; //右移4位
x=x&0x0f; //和前面兩句就是取出t[0]的高四位
t[1]=t[1]|x; //將高低字節的有效值的整數部分拼成一個字節
temperature=t[1];
TempBuffer1[1]=t[1]/100+0x30;//加0x30 為變 0~9 ASCII碼
if(TempBuffer1[1]==0x30) //如果百位為0
TempBuffer1[1]=0xfe; //百位數消隱
TempBuffer1[2]=(t[1]%100)/10+0x30;//分離出十位
TempBuffer1[3]=(t[1]%100)%10+0x30;//分離出個位
}
/*******************DS18B20函數**********************/
void delay_18B20(uint i) //延時程序
{
while(i--);
}
void Init_DS18B20(void) //ds18b20初始化函數
{
uchar x=0;
DQ = 1; //DQ復位
delay_18B20(8); //稍做延時
DQ = 0; //單片機將DQ拉低
delay_18B20(80); //精確延時大于480us
DQ = 1; //拉高總線
delay_18B20(14);
x=DQ; //稍做延時后 如果x=0則初始化成功 x=1則初始化失敗
delay_18B20(20);
}
uchar ReadOneChar(void) //ds18b20讀一個字節函數
{
unsigned char i=0;
unsigned char dat0 = 0;
for (i=8;i>0;i--)
{
DQ = 0; //讀前總線保持為低
dat0>>=1;
DQ = 1; //開始讀總線釋放
if(DQ) //從DS18B20總線讀得一位
dat0|=0x80;
delay_18B20(4); //延時一段時間
}
return(dat0); //返回數據
}
void WriteOneChar(uchar dat1) //ds18b20寫一個字節函數
{
uchar i=0;
for (i=8; i>0; i--)
{
DQ = 0; //開始寫入DS18B20總線要處于復位(低)狀態
DQ = dat1&0x01; //寫入下一位
delay_18B20(5);
DQ = 1; //重新釋放總線
dat1>>=1; //把一個字節分成8個BIT環移給DQ
}
}
void ReadTemperature() //讀取ds18b20當前溫度
{
delay_18B20(80); //延時一段時間
Init_DS18B20();
WriteOneChar(0xCC); // 跳過讀序號列號的操作
WriteOneChar(0x44); // 啟動溫度轉換
delay_18B20(80); // 延時一段時間
Init_DS18B20(); //DS18B20初始化
WriteOneChar(0xCC); //跳過讀序號列號的操作
WriteOneChar(0xBE); //讀取溫度寄存器等(共可讀9個寄存器) 前兩個就是溫度
delay_18B20(80); //延時一段時間
t[0]=ReadOneChar(); //讀取溫度值低位
t[1]=ReadOneChar(); //讀取溫度值高位
}
void delay_motor(uchar i) //延時函數
{
uchar j,k; //變量i、k為無符號字符數據類型
for(j=i;j>0;j--) //循環延時
for(k=200;k>0;k--); //循環延時
}
/*******************電機轉動程序*******************/
void motor(uchar tmp)
{
uchar x;
if(TempBuffer1[0]==0x2b) //溫度為正數
{
if(tmp<25) //溫度小于25度
{
D=0; //電機停止轉動
PWM=0;
}
else if(tmp>50) //溫度大于50度,全速轉動
{
D=0; //D置0
PWM=1; //正轉,PWM=1
x=250; //時間常數為x
delay_motor(x); //調延時函數
PWM=0; // PWM=0
x=5; //時間常數為x
delay_motor(x); //調延時函數
}
else
{
D=0; //D置0
PWM=1; //正轉,PWM=1
x=5*tmp; //時間常數為x
delay_motor(x); //調延時函數
PWM=0; // PWM=0
x=255-5*tmp; //時間常數為255-x
delay_motor(x); //調延時函數
}
}
else if (TempBuffer1[0]==0x2d) //溫度小于0,反轉
{
D=1;
PWM=0; // PWM=0
x=5*tmp; //時間常數為tmp
delay_motor(x); //調延時函數
PWM=1; // PWM=1
x=255-5*tmp; //時間常數為255- tmp
delay_motor(x); //調延時函數
}
}
void delay(unsigned int x) //延時函數名
{
unsigned char i; //定義變量i的類型
while(x--) //x自減1
{
for(i=0;i<123;i++){;} //控制延時的循環
}
}
/*************************main主程序*********************/
void main(void)
{
delay_20ms(); //系統延時20ms啟動
ReadTemperature(); //啟動DS18B20
Init_lcd(); //調用LCD初始化函數
LCD_Print(0,0,tab); //液晶初始顯示
delay(1000); //延時一段時間
while(1)
{
ReadTemperature(); //讀取溫度,溫度值存放在一個兩個字節的數組中,
delay_18B20(100);
covert1(); //數據轉化
LCD_Print(4,1,TempBuffer1); //顯示溫度
motor(temperature); //電機轉動
}
}
復制代碼
TEMPER_L EQU 31H ;用于保存讀出溫度的低字節
TEMPER_H EQU 30H ;用于保存讀出溫度的高字節
T_INTEGER EQU 32H ;溫度的整數部分(integer)
T_IN_BAI EQU 35H ;溫度的百位
T_IN_SHI EQU 36H ;溫度的十位
T_IN_GE EQU 37H ;溫度的個位
FLAG BIT 33H ;標志位
TEMPHC EQU 34H ;正、負溫度值標記
SPEED EQU 45H ;電機的速度調節位
RW BIT P2.1 ;LCD1602R/W引腳由P2.1引腳控制
RS BIT P2.0 ;LCD1602RS引腳由P2.0引腳控制
E BIT P2.2 ;LCD1602E引腳由P2.2引腳控制
DQ BIT P1.7 ;DS18B20數據線
PWM BIT P3.6 ;定義速度控制位PWMP3.7
D BIT P3.7 ;定義方向控制位P3.2
ORG 0000H ;在0000H單元存放轉移指令
SJMP MAIN ;轉移到主程序
ORG 0060H ;主程序從0060H開始
MAIN: LCALL DELAY20ms ;系統延時20ms啟動
LCALL INIT ;調用LCD初始化函數
LCALL MENU ;調用液晶初始界面
LCALL READ_TEM ;開啟DS18B20
LCALL DELAY1S ;調用1s延時,使DS18B20能完全啟動
LOOP: LCALL READ_TEM ;讀取溫度,溫度值存放
LCALL CONVTEMP ;調用溫度轉化程序
LCALL DISPLAY ;調用顯示程序
LCALL MOTOR ;調用電機轉動程序
LJMP LOOP ;循環調用
DELAY1S:MOV R5,#10 ;1S延時程序,給R5賦值,外循環控制
DEL1: MOV R6,#200 ;中循環控制
DEL2: MOV R7,#250 ;內循環控制
DEL3: DJNZ R7,DEL3 ;內循環體
DJNZ R6,DEL2 ;中循環體
DJNZ R5,DEL1 ;外循環體
RET ;子程序返回
;------------------------電機轉動程序----------------------
MOTOR: MOV A,T_INTEGER ;溫度轉化的整數暫存于A中
MOV B,#5 ;給寄存器賦值立即數5
MUL AB ;整數*5,提高轉速的占空比
MOV SPEED,A
MOV A,TEMPHC ;把正、負溫度值標記暫存于A中
CJNE A,#0AH,NEG ;判斷溫度值標記是正還是負,如果是正,就順序執行;否則,跳轉到NEG
CLR C ;把進位清零
WIN: MOV A,T_INTEGER ;溫度轉化的整數暫存于A中
SUBB A,#25 ;判斷溫度是否超過25度
JNC POS ;溫度大于25度,跳轉到POS
SETB D ;方向控制端置1
SETB PWM ;PWM端置1,電機停止轉動
JMP REND ;子程序返回
POS: MOV A,T_INTEGER ;溫度轉化的整數暫存于A中
SUBB A,#50 ;判斷溫度是否大于50度
JNC POS2 ;溫度大于50度,跳轉到POS2
POS1: SETB D ;方向控制端置1
CLR PWM ;正轉,PWM=0
MOV A, SPEED ;時間常數為SPEED
LCALL DELAY_MOTOR ;調用電機轉動延時子程序
SETB PWM ;電機停止轉動,PWM=1
MOV A, #255 ;時間常數為255-TMP
SUBB A, SPEED
LCALL DELAY_MOTOR ;調用電機延時子程序
JMP REND ;子程序返回
POS2: MOV SPEED,#250 ;SPEED賦值為250
JMP POS1 ;跳轉到POS1
NEG: CLR D ;方向控制端置0
SETB PWM ;反轉,PWM=1
MOV A, SPEED ;時間常數為SPEED
LCALL DELAY_MOTOR ;調用電機延時子程序
CLR PWM ;PWM=0
MOV A, #255 ;時間常數為255-TMP
SUBB A, SPEED
LCALL DELAY_MOTOR ;調用延時子程序
REND: RET ;子程序返回
;---------------------電機轉動延時子程序--------------------------
DELAY_MOTOR:MOV R6, #5 ;設循環次數
D1: DJNZ R6, D1 ;循環等待
DJNZ ACC,D1 ;循環等待
RET ;子程序返回
;---------------------溫度轉化程序------------------------------
CONVTEMP: MOV A,TEMPER_H ;判溫度是否零下
ANL A,#08H
JZ TEMPC1 ;溫度沒有零下,跳轉到TEMPC1
CLR C ;進位清零
MOV A,TEMPER_L ;溫度的低字節二進制數求補
CPL A ;取反
ADD A,#01H ;加1
MOV TEMPER_L,A
MOV A,TEMPER_H ;溫度的高字節二進制數求補(雙字節)
CPL A ;取反
ADDC A,#00H
MOV TEMPER_H,A
MOV TEMPHC,#0BH ;負溫度標志
LJMP TEMPC11 ;跳轉到TEMPC11
TEMPC1: MOV TEMPHC,#0AH ;正溫度標志
TEMPC11: MOV A,TEMPER_L
ANL A,#0F0H ;取出高四位
SWAP A
MOV TEMPER_L,A
MOV A,TEMPER_H ;取出低四位
ANL A,#0FH
SWAP A
ORL A,TEMPER_L ;把溫度的高字節和低字節重新組合為一個字節
MOV T_INTEGER,A ;把組合成字節存于T_INTEGER
MOV B,#100 ;把溫度整數部分化為BCD碼
DIV AB
MOV T_IN_BAI,A
MOV A,B
MOV B ,#10
DIV AB
MOV T_IN_SHI,A
MOV T_IN_GE,B
RET
;----------------------讀溫度程序---------------------------------
READ_TEM: LCALL Set_18B20 ;DS18B20初始化
MOV A,#0CCH ;跳過ROM匹配
LCALL WRITE_1820 ;寫DS18B20的子程序
MOV A,#44H ;發出溫度轉換命令
LCALL WRITE_1820 ;寫DS18B20的子程序
LCALL Set_18B20 ;準備讀溫度前先初始化
MOV A,#0CCH ;跳過ROM匹配
LCALL WRITE_1820 ;寫DS18B20的子程序
MOV A,#0BEH ;發出讀溫度命令
LCALL WRITE_1820 ;寫DS18B20的子程序
LCALL READ_1820 ;讀DS18B20的程序
RET ;子程序返回
;--------------------------DS18B20初始化程序--------------------------
Set_18B20:SETB DQ ;數據線拉高
NOP
CLR DQ ;賦值數據線低電平
MOV R2,#255 ;主機發出延時500微秒的復位低脈沖
DJNZ R2,$
SETB DQ ;拉高數據線
MOV R2,#30
DJNZ R2,[ DISCUZ_CODE_3 ]nbsp; ;延時60us等待DS18B20回應
JNB DQ,INIT1
JMP Set_18B20 ;超時而沒有響應,重新初始化
INIT1: MOV R2,#120
DJNZ R2,[ DISCUZ_CODE_3 ]nbsp; ;延時240us
JB DQ,INIT2 ;數據變高,初始化成功
JMP Set_18B20 ;初始化失敗,重新初始化
INIT2: MOV R2,#240
DJNZ R2,$
RET
;-----------------寫DS18B20的子程序(有具體的時序要求)-----------------
WRITE_1820:
MOV R2,#8 ;一共8位數據
WR0: CLR DQ ;開始寫入DS18B20總線要處于復位
MOV R3,#6 ;總線復位保持14微妙以上
DJNZ R3,$
RRC A ;把一個字節分成8個BIT環移給C
MOV DQ,C
MOV R3,#20 ;等待40微妙
DJNZ R3,$
SETB DQ ;重新釋放總線
NOP
NOP
DJNZ R2,WR0 ;寫入下一位
SETB DQ
RET
;------ 從DS18B20中讀出兩個字節的溫度數據--------
READ_1820:
MOV R4,#2 ;將溫度高位和低位從DS18B20中讀出
MOV R1,#TEMPER_L ;低位存入31H(TEMPER_L)
RE0: MOV R2,#8
RE1: SETB DQ ;數據總線拉高
NOP
NOP
CLR DQ ;讀前總線保持為低
NOP
NOP
SETB DQ ;開始讀總線釋放
MOV R3,#4 ;延時一段時間
DJNZ R3,$
MOV C,DQ ;從DS18B20總線讀得一位
RRC A ;把讀得的位值環移給A
MOV R3,#30 ;延時一段時間
DJNZ R3,$
DJNZ R2,RE1 ;讀下一位
MOV @R1,A
DEC R1 ;高位存入30H(TEMPER_H)
DJNZ R4,RE0
RET
;------------------------------顯示程序----------------------
DISPLAY: MOV A,#0C4H ;設定顯示位置
LCALL WRC ;調用寫入命令程序
MOV A, TEMPHC ;判斷溫度是正還是負
CJNE A,#0BH,FZ ;如果溫度是負,順序執行;是正,跳轉到FZ
MOV A,#2DH ;"-"號顯示
AJMP WDA ;跳轉到WDA
FZ: MOV A,#2BH ;"+"號不顯示
WDA: LCALL WRD ;寫數據
MOV R0,#35H ;顯示溫度的百位、十位、個位
WDA1: MOV A,@R0
ADD A,#30H
LCALL WRD ;寫數據
INC R0
CJNE R0,#38H,WDA1 ;判斷溫度是否顯示完
MOV A,#0C9H ;設定顯示位置
LCALL WRC ;寫入命令
MOV A,#0DFH ;"。"的ASCII碼
LCALL WRD ;寫數據
MOV A,#043H ;"C"的ASCII碼
LCALL WRD ;寫數據
RET ;子程序返回
;******** 顯示正確信息子程序 ***************
MENU: MOV DPTR,#M_1 ;指針指到顯示消息
LINE1: MOV A,#80H ;設置 LCD 的第一行地址
LCALL WRC ;寫入命令
FILL: CLR A ;填入字符
MOVC A,@A+DPTR ;由消息區取出字符
CJNE A,#0,LC1 ;判斷是否為結束碼
JMP RET_END ;子程序返回
LC1: LCALL WRD ;寫入數據
INC DPTR ;指針加1
JMP FILL ;繼續填入字符
RET_END: RET
M_1: DB " T Monitor ",0
;---------------液晶初始化程序-----------------
INIT: MOV A,#01H ;清屏
LCALL WRC ;調用寫命令子程序
MOV A,#38H ;8位數據,2行,5×8點陣
LCALL WRC ;調用寫命令子程序
MOV A,#0cH ;開顯示和光標,字符不閃爍
LCALL WRC ;調用寫命令子程序
MOV A,#06H ;字符不動,光標自動右移1格
LCALL WRC ;調用寫命令子程序
RET ;子程序返回
;---------------忙檢查子程序-------------
CBUSY: PUSH ACC ;將A的值暫存于堆棧
PUSH DPH ;將DPH的值暫存于堆棧
PUSH DPL ;將DPL的值暫存于堆棧
PUSH PSW ;將PSW的值暫存于堆棧
WEIT: CLR RS ;RS=0,選擇指令寄存器
SETB RW ;RW=1,選擇讀模式
CLR E ;E=0,禁止讀/寫LCD
SETB E ;E=1,允許讀/寫LCD
NOP
MOV A,P0 ;讀操作
CLR E ;E=0,禁止讀/寫LCD
JB ACC.7,WEIT ;忙碌循環等待
POP PSW ;從堆棧取回PSW的值
POP DPL ;從堆棧取回DPL的值
POP DPH ;從堆棧取回DPH的值
POP ACC ;從堆棧取回A的值
LCALL DELAY ;延時
RET ;子程序返回
;---------------寫子程序-------------
……………………
…………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
所有資料51hei提供下載:
2溫度監控系統.zip
(115.41 KB, 下載次數: 43)
2021-6-10 22:05 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
歡迎光臨 (http://www.zg4o1577.cn/bbs/)
Powered by Discuz! X3.1
主站蜘蛛池模板:
heyzo在线
|
av在线一区二区三区
|
国产精品一区二区三区久久久
|
四虎影院在线播放
|
伊人久久麻豆
|
亚洲欧美国产视频
|
欧美区日韩区
|
91久久国产综合久久
|
91精品国产综合久久精品图片
|
久久精品在线
|
国产视频福利
|
国产精品久久毛片av大全日韩
|
国产精品久久99
|
国产欧美日韩一区二区三区在线观看
|
高清一区二区三区
|
国户精品久久久久久久久久久不卡
|
欧美高清视频一区
|
亚洲精品美女
|
www.4虎影院 国产999精品久久久影片官网
|
91新视频
|
亚洲综合色丁香婷婷六月图片
|
亚洲高清视频在线观看
|
欧美成年黄网站色视频
|
一区二区在线看
|
一区二区三区四区日韩
|
亚洲成人动漫在线观看
|
天堂网av在线
|
91就要激情
|
别c我啊嗯国产av一毛片
|
日本视频中文字幕
|
欧美性网站
|
久久人人网
|
成年人网站在线观看视频
|
精品国产一区二区三区免费
|
黄色成人免费在线观看
|
日本免费一区二区三区四区
|
成年人免费网站
|
欧美区在线
|
超碰日本
|
亚洲有码转帖
|
拍真实国产伦偷精品
|