写的程序前几天运行都是正确的,今天运行就全是翱字,拿手碰一下才会正常显示
#include "msp430f149.h"
typedef unsigned char uchar; //给个新名字代替,这里不涉及struct
typedef unsigned int uint; //在有指针的场合,typedef要比#define好,无符号类型能保存2倍于有符号类型的正整数数据
//DS18B20端口设置
#define DQ1 P2OUT|=BIT4 //DQ置位
#define DQ0 P2OUT&=~BIT4 //DQ复位
#define DQ_in P2DIR&=~BIT4 //设DQ为输入
#define DQ_out P2DIR|=BIT4 //设DQ为输出
#define DQ_val (P2IN&BIT4) //读DQ电平
//通过定时器A实现精确的N个微秒的延时,因为DS18B20是one-wire类型,对时间的要求非常严格
void DelayNus(uint n)
{
TACTL|=TASSEL_2+ID_3+MC_1; //SMCLK,8分频,增计数模式
//CCTL0|=CCIE; //中断允许
CCR0=n; //CCR0=1时捕捉的是1us(n/1M)
while(!(TACTL&BIT0)); //等待定时Nus后置位中断标志TAIFG while(!TAIFG) 1即有中断发生
TACTL=TACLR; //停止计数,在于清除了计数器设置,TACLR=1
TACTL&=~BIT0; //清除中断标志TAIFG
}
//初始化DS18B20,等待DS18B20回复一个presence pulse,若在60-240us内读到回复的脉冲信号,表示DS18B20存在
uchar Init_18B20(void)
{
uchar flag; //定义一标志信号,1失败,0成功,
DQ_out; //设置DQ为输出,可不要
DQ0; //拉低总线
DelayNus(500); //延时500us,产生复位脉冲(480-960)
DQ1; //释放总线
DelayNus(65); //等待15-60us,且要在60-240us内读到返回的脉冲信号,计算后得到延时时间最好要在60-75us
DQ_in; //DQ设置为输入状态,以读取DS18B20存在状态,必须要有
DelayNus(5); //短暂延时一下确保读取成功
if(DQ_val) //若读到高电平则无DS18b20
{
flag=1; //初始化失败
}
else
{
flag=0; //初始化成功
}
DQ_out; //设置DQ为输出,必须要有
DQ1; //释放总线
DelayNus(400); //>=480us
return flag; //返回标志信号
}
//单片机向DS18B20写入一个字节的数据,内部具体包括写0、1
void Write_18B20(uchar wdata)
{
uchar i;
for(i=0x01;i!=0;i<<=1) //一个字共有8位,读写都从低位开始
{
DQ0; //拉低总线,
DelayNus(5); //延时5us,至少1us
if((wdata&i)==0) //满足则末尾是0,即写入的是0
DQ0; //写0单片机输出低电平
else //不满足就是末尾为1,即写入1
DQ1; //写1单片机输出高电平
DelayNus(50); //15-60us
DQ1; //释放总线,等待总线恢复
DelayNus(10); //延时10us
}
}
//单片机从DS18B20读取一个字节(8bit)的数据
uchar Read_18B20(void)
{
uchar i; //当作检测信号
uchar temp; //temp用于存储从DS18B20读取出来的8位数据
for(i=0x01;i!=0;i<<=1)
{
DQ0; //拉低总线,产生读信号
DelayNus(5); //延时5us,至少1us
DQ1; //释放总线,准备读数据
DelayNus(5); //延时5us
DQ_in; //设置为输入状态,以读取数据
_NOP(); //必须在15us内读取DS18B20发送的数据位
if(DQ_val)
{
temp=temp|i; //读1就写1
}
else
{
temp=temp&(~i); //读0就写0
}
DelayNus(45); //延时45us
DQ_out; //设置端口为输出
DQ1; //释放总线
DelayNus(10);
}
return temp; //返回从DS18B20读出的8位数据
}
//让DS18B20开始转换温度
void ChangeTemp(void)
{
uchar i;
Init_18B20();
Write_18B20(0xcc); //跳过ROM配置(skip rom),单线直接这样设置
Write_18B20(0x44); //启动温度转换(默认值+85),有了这句话才会开始测量温度
for(i=20;i>0;i--)
DelayNus(60000); //延时800ms以上,若是一直刷着,就不用这个延时
//一分钟延时就可以一分钟检测一次
}
//发送读取温度命令
void ReadTempCom(void)
{
Init_18B20();
Write_18B20(0xcc); //都需要3步(1.初始化2.rom设置3.写字节)
Write_18B20(0xbe); //发送读ScratchPad命令
}
//从DS18B20的ScratchPad读取温度转换结果
uint Do1Convert(void)
{
uchar i;
uchar temp_l; //char是8bit,先存放低位
uint realtemp; //int是16bit
do
{
i=Init_18B20(); //把flag的值赋给I,判断是否初始换成功
}
while(i); //0成功跳出
ChangeTemp(); //先写转换命令
ReadTempCom(); //然后等待转换完后发送读取温度命令
temp_l=Read_18B20(); //读取温度值共16位,必须先读低字节
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 //数据
#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 //使能关
#define LCD_DataIn P4DIR=0x00 //数据口方向设置为输入
#define LCD_DataOut P4DIR=0xff //数据口方向设置为输出
#define LCD2MCU_Data P4IN //LCD向单片机输入数据
#define MCU2LCD_Data P4OUT //单片机向LCD输出数据
#define LCD_CMDOut P3DIR|=0x07 //P3口的低三位(RS,RW,EN)设置为输出
#define LCD_PSB_H P3OUT|=BIT3 //并行
#define LCD_PSB_L P3OUT&=~BIT3 //串行
#define LCD_RST_L P3OUT&=~BIT4 //复位 低电平有效
//延时约1ms程序
void Delay_1ms(void)
{
uchar i;
for(i=150;i>0;i--);
_NOP(); //延时几us,自带函数,用于短暂延时
}
//延时N个1ms的时间
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口的低三位设置为输出
LCD_RS_L; //命令
LCD_RW_H; //读
LCD_DataIn; //P4端口设置为输出
do //判忙判断的是最高位数据
{
LCD_EN_H;
_NOP();
lcdtemp = LCD2MCU_Data; //读取LCD忙碌状态
LCD_EN_L;
}
while(lcdtemp&0x80); //若为0表示不忙,一直等到LCD不忙(即最高位是0)才跳出函数
}
//写命令
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;
}
//写数据
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++));
}
/*****读数据
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; //寄存数据
LCD_EN_L;
return RData; //返回读到的数据
}
*****/
//初始化液晶显示屏
void Init_Lcd(void)
{
//LCD_RST_L; //复位
LCD_PSB_H; //并行
LCD_CMDOut; //液晶控制端口设置为输出
Delay_Nms(500);
Write_Cmd(0x30); //基本指令集
Delay_1ms();
Write_Cmd(0x02); // 地址归位
Delay_1ms();
Write_Cmd(0x0c); //整体显示打开,游标关闭
Delay_1ms();
Write_Cmd(0x01); //清除显示
Delay_1ms();
Write_Cmd(0x06); //游标右移
Delay_1ms();
Write_Cmd(0x80); //设定显示的起始地址
}
/*****
//在坐标(x,y)处连续显示一个字符串,共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)) //字符串数组末尾有一个'/0',用i自加让他每位都取到并判断是否自加到末尾
{
Write_Data(*(adata+i));
i++;
}
}
*****/
#include <msp430f149.h>
#include "LCD12864.h" //声明所有调用函数库
#include "DS18B20.h"
uchar line1[]={"检测的温度值为:"}; //先定义要显示的汉字
uchar *str1=line1; //str表示指针,可以存放地址,这句话的意思就是把"检"的地址赋给指针变量str1,所以*str1的值就是"检"
uchar dN[6]; //存放转换完成的温度
void Disp_Numb(uint realtemp); //先声明后面要用到的函数
void main(void)
{
uchar i;
WDTCTL=0x5A80;
//430中,一个时钟周期=MCLK晶振的倒数,如MCLK是8M,则时钟周期为1/8us
BCSCTL1&=~XT2OFF; //打开XT2高频晶体振荡器,选择系统主时钟为8MHz
do
{
IFG1&=~OFIFG; //清除晶振失败标志
for(i=0xFF;i>0;i--); //等待8MHz晶体起振,稳定时间
}
while((IFG1&OFIFG)); //若晶振失效标志仍存在
BCSCTL2|=SELM_2+SELS; //选择MCLK和SMCLK为XT2
TACTL|=TASSEL_2+ID_3; //计数时钟选择SMLK=8MHz,8分频
Init_Lcd(); //液晶初始化
while(1) //循环进行温度数值转换
{
Disp_Numb(Do1Convert()); //将十一位的温度值转换成六位整数
Disp_HZ(0x80,line1,8);
//在12864显示温度值
//0x30 表示字符‘0’,所有数字都加‘0’表示将十进制的数转换成相应数字的字符对应的ASCII值
Write_Cmd(0x90); //第二行
Write_Data(dN[5]+0x30); //十位
Write_Data(dN[4]+0x30); //个位
Write_Data('.'); //小数点
Write_Data(dN[3]+0x30); //十分位
Write_Data(dN[2]+0x30); //百分位
Write_Data(dN[1]+0x30); //千分位
Write_Data(dN[0]+0x30); //万分位
}
}
//将从DS18B20读取的温度数据转换成六位整数,并存储在字符数组dN【6】中
//顺序是 5 4 . 3 2 1 0,依次是十位,个位,十分位···
//因为是数字体温计,常理来说不存在负温度,若是负温度,则需要取反加1
void Disp_Numb(uint realtemp)
{
uchar i;
for(i=6;i>0;i--) //6次
dN=0; //先置0
//数值转换算法,将十一位二进制温度值转换成六位整型数据
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) //判断是否需要进位
{ //百分位是6+2+5级满足条件
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;
}
}
}
|