|
发表于 2009-11-24 11:52:14
|
显示全部楼层
终于调通了,^_^ 谢谢xiaoluo
主要是因为程序中的18b20的读写延时有点问题,经过修改,终于调通了。同时做四位小数运算时,最好用乘法运算。除法有点问题。
/*MCU:ATmega16
CLK:1M
PC4:RS
PC5:R/W
PC6:E
PA0--PA7:液晶1602数据双向口
PB7;ds18b20数据I/O口
*/
#include<iom16v.h>
#include<macros.h>
#define uchar unsigned char
#define uint unsigned int
#define rs_h PORTC |= BIT(4)
#define rs_l PORTC &= ~BIT(4)
#define rw_h PORTC |= BIT(5)
#define rw_l PORTC &= ~BIT(5)
#define e_h PORTC |= BIT(6)
#define e_l PORTC &= ~BIT(6)
#define DQ_H PORTB |= BIT(7)
#define DQ_L PORTB &= ~BIT(7)
uchar temp;
float temp_dec; //做小数运算一定要用浮点型
uint temp_dec_F; //小数扩大10000后数值超过255,至少用int
//温度的整数,温度的小数变量
uchar lcd[11]={"0123456789."};
uchar b_d[7]={0};
/****************************/
void delay_ms(uint x)
{
uchar i;
while(x--)
{
for(i=0;i<100;i++);
}
}
/**************************/
void delay_us(uint x)
{
while(x--);
}
/***************************/
void port_init(void)
{
DDRC |= BIT(4)|BIT(5)|BIT(6);
PORTC &= ~(BIT(4)|BIT(5)|BIT(6));
DDRA=0XFF;
PORTA=0X00;
DDRB |= BIT(7);
PORTB |= BIT(7);
//DDRB |= BIT(1);
//PORTB |= BIT(1);
}
/********18b20*****************/
void reset(void) //复位函数
{ //DDRB |= BIT(7); //有没有此句都行,port_init()已经初始化,否则此句必须有。
DQ_H; //数据线高
DQ_L; //把数据线拉低
delay_us(80); //延时480us
DQ_H; //释放总线。
DDRB &= ~BIT(7); //改变PB0口的方向
delay_us(10); //延时60us
while( PINB&BIT(7) ); //复位成功
delay_us(40); //延时240us ,没有此延时,下面延时必须有。
//PORTB &= ~BIT(1); //检测一下是不是在死循环里了.
DDRB |= BIT(7);
DQ_H; //再次释放总线
//delay_us(40); //此句与上面延时二者必有其一,或都有。
}
/***************************/
void write_byte(uchar x)
{
uchar i,j;
for(i=0;i<8;i++)
{
DQ_L; //拉低数据线,空闲时是为高电平
for(j=0;j<1;j++);//延时9us,没有此句也行
//delay_us(1); //15us不行, 此处延时必须小于15us
if( ( x&0x01 )==0x01 )
DQ_H;
else
DQ_L;
delay_us(5); //45us
DQ_H; //释放总线,以便于下次进for语句时,DQ_H;是为高电平.
x>>=1;
}
DQ_H; //没有此句也行,因为每次循环末尾都有
}
/********************************/
uchar read_byte(void) //ds18b20读一字节
{
uchar i,j,z;
z=0;
for(i=0;i<8;i++)
{
z>>=1;
DQ_L; //拉低数据线,空闲时是为高电平
DQ_H; //释放总线
for(j=0;j<1;j++);//延时9us,没有此句也行
//delay_us(1); //延时15us 不行, 此处延时必须小于15us
DDRB &= ~BIT(7);
if( ( PINB&BIT(7) )==0X80 )
z|=0x80;
else
z&=0x7f;
delay_us(10); //延时60us
DDRB |= BIT(7);
DQ_H; //再次释放总线
}
return(z);
}
/*******************************/
void get_time(void)
{
uchar temp_l,temp_h,i;
reset(); //复位.
write_byte(0xcc); //跳过ROM.
write_byte(0x44); //温度转换.
delay_ms(1000); //延时2秒.
reset(); //复位.
write_byte(0xcc); //跳过ROM.
write_byte(0xbe); //读暂存存储器.
temp_l=read_byte(); //温度存储器中的温度低8位.
temp_h=read_byte(); //温度存储器中的高8位.
reset(); //再来个复位,终止读暂存存储器.
i=temp_l;
i &= 0x0f; //温度的低四位.
temp_dec=i*0.0625; //温度的小数. 此处用乘法,如果用除16,则会显示乱码
temp_dec_F=temp_dec*10000; //放大10000倍,当除以1000时才能得到第一位小数。
temp_l>>=4; //把小数点移掉,得到温度整数的个位,既低四位。
temp_h<<=4; //把前面4个符号位移掉,只保留一位符号位和温度的高三位。
temp = temp_l|temp_h; //温度的整数.
}
/*******************************/
void b_d_data(void) //数据处理
{
b_d[0]=temp/100; //温度的百位.
b_d[1]=temp%100/10;//温度的十位.
b_d[2]=temp%100%10;//温度的个位.
b_d[3]=temp_dec_F/1000;//小数的第一位
b_d[4]=temp_dec_F%1000/100;//小数的第二位
b_d[5]=temp_dec_F%1000%100/10;//小数的第三位
b_d[6]=temp_dec_F%1000%100%10;//小数的第四位
}
/********1602液晶***************/
void busy(void) //1602判断忙函数
{
DDRA=0X00;
rs_l;
rw_h;
e_h;
while( ( PINA&0x80 )==0x80 );
e_l;
DDRA=0xff;
}
/******************************/
void write_com(uchar com) //1602液晶写命令
{
busy();
PORTA=0x00;
rs_l;
rw_l;
PORTA=com;
e_h;
e_l;
PORTA=0x00;
}
/*****************************/
void write_data(uchar data) //1602写数据
{
busy();
PORTA=0x00;
rs_h;
rw_l;
e_h;
PORTA=data;
e_l;
PORTA=0x00;
}
/*****************************/
void init_1602(void)
{
write_com(0x38); //1602显示模式设置
write_com(0x01); //清显示
delay_ms(2);
write_com(0x0c); //开显示,不显示光标,光标不闪烁。
write_com(0x06); //当写一字符时,地址加一,而且光标加一.
}
void disp_lcd(void) //显示刷新
{
write_com(0x80+0x04); //显示地址
write_data(lcd[b_d[0]]);
write_data(lcd[b_d[1]]);
write_data(lcd[b_d[2]]);
write_data(lcd[10]);
write_data(lcd[b_d[3]]);
write_data(lcd[b_d[4]]);
write_data(lcd[b_d[5]]);
write_data(lcd[b_d[6]]);
}
/**************************/
void main(void)
{
port_init();
init_1602();
while(1)
{
get_time();
b_d_data();
disp_lcd();
}
} |
|