|
寫的程序前幾天運(yùn)行都是正確的,今天運(yùn)行就全是翱字,拿手碰一下才會(huì)正常顯示
#include "msp430f149.h"
typedef unsigned char uchar; //給個(gè)新名字代替,這里不涉及struct
typedef unsigned int uint; //在有指針的場合,typedef要比#define好,無符號(hào)類型能保存2倍于有符號(hào)類型的正整數(shù)數(shù)據(jù)
//DS18B20端口設(shè)置
#define DQ1 P2OUT|=BIT4 //DQ置位
#define DQ0 P2OUT&=~BIT4 //DQ復(fù)位
#define DQ_in P2DIR&=~BIT4 //設(shè)DQ為輸入
#define DQ_out P2DIR|=BIT4 //設(shè)DQ為輸出
#define DQ_val (P2IN&BIT4) //讀DQ電平
//通過定時(shí)器A實(shí)現(xiàn)精確的N個(gè)微秒的延時(shí),因?yàn)镈S18B20是one-wire類型,對(duì)時(shí)間的要求非常嚴(yán)格
void DelayNus(uint n)
{
TACTL|=TASSEL_2+ID_3+MC_1; //SMCLK,8分頻,增計(jì)數(shù)模式
//CCTL0|=CCIE; //中斷允許
CCR0=n; //CCR0=1時(shí)捕捉的是1us(n/1M)
while(!(TACTL&BIT0)); //等待定時(shí)Nus后置位中斷標(biāo)志TAIFG while(!TAIFG) 1即有中斷發(fā)生
TACTL=TACLR; //停止計(jì)數(shù),在于清除了計(jì)數(shù)器設(shè)置,TACLR=1
TACTL&=~BIT0; //清除中斷標(biāo)志TAIFG
}
//初始化DS18B20,等待DS18B20回復(fù)一個(gè)presence pulse,若在60-240us內(nèi)讀到回復(fù)的脈沖信號(hào),表示DS18B20存在
uchar Init_18B20(void)
{
uchar flag; //定義一標(biāo)志信號(hào),1失敗,0成功,
DQ_out; //設(shè)置DQ為輸出,可不要
DQ0; //拉低總線
DelayNus(500); //延時(shí)500us,產(chǎn)生復(fù)位脈沖(480-960)
DQ1; //釋放總線
DelayNus(65); //等待15-60us,且要在60-240us內(nèi)讀到返回的脈沖信號(hào),計(jì)算后得到延時(shí)時(shí)間最好要在60-75us
DQ_in; //DQ設(shè)置為輸入狀態(tài),以讀取DS18B20存在狀態(tài),必須要有
DelayNus(5); //短暫延時(shí)一下確保讀取成功
if(DQ_val) //若讀到高電平則無DS18b20
{
flag=1; //初始化失敗
}
else
{
flag=0; //初始化成功
}
DQ_out; //設(shè)置DQ為輸出,必須要有
DQ1; //釋放總線
DelayNus(400); //>=480us
return flag; //返回標(biāo)志信號(hào)
}
//單片機(jī)向DS18B20寫入一個(gè)字節(jié)的數(shù)據(jù),內(nèi)部具體包括寫0、1
void Write_18B20(uchar wdata)
{
uchar i;
for(i=0x01;i!=0;i<<=1) //一個(gè)字共有8位,讀寫都從低位開始
{
DQ0; //拉低總線,
DelayNus(5); //延時(shí)5us,至少1us
if((wdata&i)==0) //滿足則末尾是0,即寫入的是0
DQ0; //寫0單片機(jī)輸出低電平
else //不滿足就是末尾為1,即寫入1
DQ1; //寫1單片機(jī)輸出高電平
DelayNus(50); //15-60us
DQ1; //釋放總線,等待總線恢復(fù)
DelayNus(10); //延時(shí)10us
}
}
//單片機(jī)從DS18B20讀取一個(gè)字節(jié)(8bit)的數(shù)據(jù)
uchar Read_18B20(void)
{
uchar i; //當(dāng)作檢測信號(hào)
uchar temp; //temp用于存儲(chǔ)從DS18B20讀取出來的8位數(shù)據(jù)
for(i=0x01;i!=0;i<<=1)
{
DQ0; //拉低總線,產(chǎn)生讀信號(hào)
DelayNus(5); //延時(shí)5us,至少1us
DQ1; //釋放總線,準(zhǔn)備讀數(shù)據(jù)
DelayNus(5); //延時(shí)5us
DQ_in; //設(shè)置為輸入狀態(tài),以讀取數(shù)據(jù)
_NOP(); //必須在15us內(nèi)讀取DS18B20發(fā)送的數(shù)據(jù)位
if(DQ_val)
{
temp=temp|i; //讀1就寫1
}
else
{
temp=temp&(~i); //讀0就寫0
}
DelayNus(45); //延時(shí)45us
DQ_out; //設(shè)置端口為輸出
DQ1; //釋放總線
DelayNus(10);
}
return temp; //返回從DS18B20讀出的8位數(shù)據(jù)
}
//讓DS18B20開始轉(zhuǎn)換溫度
void ChangeTemp(void)
{
uchar i;
Init_18B20();
Write_18B20(0xcc); //跳過ROM配置(skip rom),單線直接這樣設(shè)置
Write_18B20(0x44); //啟動(dòng)溫度轉(zhuǎn)換(默認(rèn)值+85),有了這句話才會(huì)開始測量溫度
for(i=20;i>0;i--)
DelayNus(60000); //延時(shí)800ms以上,若是一直刷著,就不用這個(gè)延時(shí)
//一分鐘延時(shí)就可以一分鐘檢測一次
}
//發(fā)送讀取溫度命令
void ReadTempCom(void)
{
Init_18B20();
Write_18B20(0xcc); //都需要3步(1.初始化2.rom設(shè)置3.寫字節(jié))
Write_18B20(0xbe); //發(fā)送讀ScratchPad命令
}
//從DS18B20的ScratchPad讀取溫度轉(zhuǎn)換結(jié)果
uint Do1Convert(void)
{
uchar i;
uchar temp_l; //char是8bit,先存放低位
uint realtemp; //int是16bit
do
{
i=Init_18B20(); //把flag的值賦給I,判斷是否初始換成功
}
while(i); //0成功跳出
ChangeTemp(); //先寫轉(zhuǎn)換命令
ReadTempCom(); //然后等待轉(zhuǎn)換完后發(fā)送讀取溫度命令
temp_l=Read_18B20(); //讀取溫度值共16位,必須先讀低字節(jié)
realtemp=Read_18B20(); //讀高位
realtemp=(realtemp<<8)|temp_l; //高8位先左移8位后再與低位相或得16位的溫度值
return realtemp; //返回讀取的溫度值
}
#include "msp430f149.h"
typedef unsigned char uchar;
typedef unsigned int uint;
//LCD12864端口配置
#define LCD_RS_H P3OUT|=BIT0 //數(shù)據(jù)
#define LCD_RS_L P3OUT&=~BIT0 //指令
#define LCD_RW_H P3OUT|=BIT1 //讀
#define LCD_RW_L P3OUT&=~BIT1 //寫
#define LCD_EN_H P3OUT|=BIT2 //使能開
#define LCD_EN_L P3OUT&=~BIT2 //使能關(guān)
#define LCD_DataIn P4DIR=0x00 //數(shù)據(jù)口方向設(shè)置為輸入
#define LCD_DataOut P4DIR=0xff //數(shù)據(jù)口方向設(shè)置為輸出
#define LCD2MCU_Data P4IN //LCD向單片機(jī)輸入數(shù)據(jù)
#define MCU2LCD_Data P4OUT //單片機(jī)向LCD輸出數(shù)據(jù)
#define LCD_CMDOut P3DIR|=0x07 //P3口的低三位(RS,RW,EN)設(shè)置為輸出
#define LCD_PSB_H P3OUT|=BIT3 //并行
#define LCD_PSB_L P3OUT&=~BIT3 //串行
#define LCD_RST_L P3OUT&=~BIT4 //復(fù)位 低電平有效
//延時(shí)約1ms程序
void Delay_1ms(void)
{
uchar i;
for(i=150;i>0;i--);
_NOP(); //延時(shí)幾u(yù)s,自帶函數(shù),用于短暫延時(shí)
}
//延時(shí)N個(gè)1ms的時(shí)間
void Delay_Nms(uint n)
{
uint i;
for(i=n;i>0;i--)
Delay_1ms();
}
//判忙
void Check_Busy(void)
{
uchar lcdtemp = 0;
LCD_CMDOut; //P3口的低三位設(shè)置為輸出
LCD_RS_L; //命令
LCD_RW_H; //讀
LCD_DataIn; //P4端口設(shè)置為輸出
do //判忙判斷的是最高位數(shù)據(jù)
{
LCD_EN_H;
_NOP();
lcdtemp = LCD2MCU_Data; //讀取LCD忙碌狀態(tài)
LCD_EN_L;
}
while(lcdtemp&0x80); //若為0表示不忙,一直等到LCD不忙(即最高位是0)才跳出函數(shù)
}
//寫命令
void Write_Cmd(uchar cmd)
{
Check_Busy(); //判忙
LCD_DataOut;
LCD_RS_L; //命令
LCD_RW_L; //寫
MCU2LCD_Data=cmd; //將命令寫入端口
LCD_EN_H;
_NOP();
LCD_EN_L;
}
//寫數(shù)據(jù)
void Write_Data(uchar dat)
{
Check_Busy();
LCD_DataOut;
LCD_RS_H;
LCD_RW_L;
MCU2LCD_Data=dat;
LCD_EN_H;
_NOP();
LCD_EN_L;
}
void Disp_HZ(uchar addr,const uchar * pt,uchar num)
{
uchar i;
Write_Cmd(addr);
for(i = 0;i < (num*2);i++)
Write_Data(*(pt++));
}
/*****讀數(shù)據(jù)
uchar Read_Data(void)
{
uchar RData;
LCD_DataIn;
Check_Busy();
LCD_RS_H;
LCD_RW_H;
LCD_EN_L;
LCD_EN_H;
RData=LCD2MCU_Data; //寄存數(shù)據(jù)
LCD_EN_L;
return RData; //返回讀到的數(shù)據(jù)
}
*****/
//初始化液晶顯示屏
void Init_Lcd(void)
{
//LCD_RST_L; //復(fù)位
LCD_PSB_H; //并行
LCD_CMDOut; //液晶控制端口設(shè)置為輸出
Delay_Nms(500);
Write_Cmd(0x30); //基本指令集
Delay_1ms();
Write_Cmd(0x02); // 地址歸位
Delay_1ms();
Write_Cmd(0x0c); //整體顯示打開,游標(biāo)關(guān)閉
Delay_1ms();
Write_Cmd(0x01); //清除顯示
Delay_1ms();
Write_Cmd(0x06); //游標(biāo)右移
Delay_1ms();
Write_Cmd(0x80); //設(shè)定顯示的起始地址
}
/*****
//在坐標(biāo)(x,y)處連續(xù)顯示一個(gè)字符串,共x*y=8*4=32處位置。
void Lcd_Print(uchar x,uchar y,uchar *adata)
{
uchar address;
uchar i=0;
if(0==y) //y=0表示第一行,x表示第幾列,共8列
{
address=0x80+x; //一行x列
}
else if(1==y)
{
address=0x90+x;
}
else if(2==y)
{
address=0x88+x;
}
else if(3==y)
{
address=0x98+x;
}
else
{
return;
}
Write_Cmd(address); //先寫地址
while(*(adata+i)) //字符串?dāng)?shù)組末尾有一個(gè)'/0',用i自加讓他每位都取到并判斷是否自加到末尾
{
Write_Data(*(adata+i));
i++;
}
}
*****/
#include <msp430f149.h>
#include "LCD12864.h" //聲明所有調(diào)用函數(shù)庫
#include "DS18B20.h"
uchar line1[]={"檢測的溫度值為:"}; //先定義要顯示的漢字
uchar *str1=line1; //str表示指針,可以存放地址,這句話的意思就是把"檢"的地址賦給指針變量str1,所以*str1的值就是"檢"
uchar dN[6]; //存放轉(zhuǎn)換完成的溫度
void Disp_Numb(uint realtemp); //先聲明后面要用到的函數(shù)
void main(void)
{
uchar i;
WDTCTL=0x5A80;
//430中,一個(gè)時(shí)鐘周期=MCLK晶振的倒數(shù),如MCLK是8M,則時(shí)鐘周期為1/8us
BCSCTL1&=~XT2OFF; //打開XT2高頻晶體振蕩器,選擇系統(tǒng)主時(shí)鐘為8MHz
do
{
IFG1&=~OFIFG; //清除晶振失敗標(biāo)志
for(i=0xFF;i>0;i--); //等待8MHz晶體起振,穩(wěn)定時(shí)間
}
while((IFG1&OFIFG)); //若晶振失效標(biāo)志仍存在
BCSCTL2|=SELM_2+SELS; //選擇MCLK和SMCLK為XT2
TACTL|=TASSEL_2+ID_3; //計(jì)數(shù)時(shí)鐘選擇SMLK=8MHz,8分頻
Init_Lcd(); //液晶初始化
while(1) //循環(huán)進(jìn)行溫度數(shù)值轉(zhuǎn)換
{
Disp_Numb(Do1Convert()); //將十一位的溫度值轉(zhuǎn)換成六位整數(shù)
Disp_HZ(0x80,line1,8);
//在12864顯示溫度值
//0x30 表示字符‘0’,所有數(shù)字都加‘0’表示將十進(jìn)制的數(shù)轉(zhuǎn)換成相應(yīng)數(shù)字的字符對(duì)應(yīng)的ASCII值
Write_Cmd(0x90); //第二行
Write_Data(dN[5]+0x30); //十位
Write_Data(dN[4]+0x30); //個(gè)位
Write_Data('.'); //小數(shù)點(diǎn)
Write_Data(dN[3]+0x30); //十分位
Write_Data(dN[2]+0x30); //百分位
Write_Data(dN[1]+0x30); //千分位
Write_Data(dN[0]+0x30); //萬分位
}
}
//將從DS18B20讀取的溫度數(shù)據(jù)轉(zhuǎn)換成六位整數(shù),并存儲(chǔ)在字符數(shù)組dN【6】中
//順序是 5 4 . 3 2 1 0,依次是十位,個(gè)位,十分位···
//因?yàn)槭菙?shù)字體溫計(jì),常理來說不存在負(fù)溫度,若是負(fù)溫度,則需要取反加1
void Disp_Numb(uint realtemp)
{
uchar i;
for(i=6;i>0;i--) //6次
dN=0; //先置0
//數(shù)值轉(zhuǎn)換算法,將十一位二進(jìn)制溫度值轉(zhuǎn)換成六位整型數(shù)據(jù)
if(realtemp&BIT0) //滿足就是最低位(2的-4次方)為1
{
dN[0]=5; //1/(2*2*2*2)=0.0625
dN[1]=2;
dN[2]=6;
}
if(realtemp&BIT1) //2的-3次方
{
dN[1]+=5; //1/2*2*2=0.125
dN[2]+=2;
dN[3]+=1;
}
if(realtemp&BIT2) //2的-2次方
{
dN[2]+=5; //1/2*2=0.25
dN[3]+=2;
if(dN[2]>=10) //判斷是否需要進(jìn)位
{ //百分位是6+2+5級(jí)滿足條件
dN[2]-=10; //百分位-1
dN[3]+=1; //十分位+1
}
}
if(realtemp&BIT3) //后面的都是如此
{
dN[3]+=5;
}
if(realtemp&BIT4)
{
dN[4]+=1;
}
if(realtemp&BIT5)
{
dN[4]+=2;
}
if(realtemp&BIT6)
{
dN[4]+=4;
}
if(realtemp&BIT7)
{
dN[4]+=8;
if(dN[4]>=10)
{
dN[4]-=10;
dN[5]+=1;
}
}
if(realtemp&BIT8)
{
dN[4]+=6;
dN[5]+=1;
if(dN[4]>=10)
{
dN[4]-=10;
dN[5]+=1;
}
}
if(realtemp&BIT9)
{
dN[4]+=2;
dN[5]+=3;
if(dN[4]>=10)
{
dN[4]-=10;
dN[5]+=1;
}
}
if(realtemp&BITA)
{
dN[4]+=4;
dN[5]+=6;
if(dN[4]>=10)
{
dN[4]-=10;
dN[5]+=1;
}
if(dN[5]>=10)
{
dN[5]-=10;
}
}
}
|
|