本帖最后由 PythonS 于 2018-11-1 10:10 编辑
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h> //中断函数头文件
//××××××××××××引脚宏定义×××××××××××××
//18B20定义
#define SET_DQ (PORTC) |= (1 <<4) // 18b20 高电平
#define CLR_DQ (PORTC) &=~(1 <<4) // 18b20 低电平
#define DQ_IN (PINC) & (1<<4) // 18b20信号输入
#define SET_OUT (DDRC) |= (1<<4) //PC4定义成输出
#define SET_IN (DDRC) &=~(1<<4) //PC4定义成输入
//常量声明
#define BAUD 9600
//全局变量声明
unsigned char Temp_H,Temp_L,OK_Flag; //温度高位,低位,复位成功标志
//函数声明
void Delayus(unsigned int lus); //us延时函数
void Delayms(unsigned int lms); //ms延时函数
void Port_DS18b20(void); //DS18B20端口配置
void Port_Init(void); //端口初始化配置
void Usart_Init(void); //USART寄存器设置
void Usart_PutChar(unsigned char cTXData); //字节发送函数
void Usart_PutString(unsigned char *pcString); //字符串发送函数
unsigned char DS18B20_Init(void); //DS18B20初始化
unsigned char Read_18b20(void); //读18b20
void Write_18b20(unsigned char dat); //写18b20
int main(void)
{
unsigned char i;
unsigned int tempint,tempint1,tempint2,tempint3,tempint4;
//分别存储温度整数值,整数值的千,百,十,个位
unsigned int temppoint,temppoint1,temppoint2,temppoint3,temppoint4;
//分别存储温度小数值,小数值的千,百,十,个位
Port_Init(); //端口初始化
Usart_Init(); //串口初始化
Port_DS18b20(); //DS18B20端口初始化
tempint = 0; //变量初始化
temppoint=0;
Temp_H = 0;
Temp_L = 0;
OK_Flag = 0;
Usart_PutString("DS18B20 温度测量实验");
Usart_PutChar(0x0D);
Usart_PutChar(0x0A); //结尾发送回车换行
sei(); //使能全局中断
while(1)
{
if(DS18B20_Init()) //判断DS18B20复位是否成功
{
PORTC = 0x00;
}
else
{
PORTC = 0x01;
}
cli(); //关中断
DS18B20_Init(); //初始化DS18B20
Write_18b20(0Xcc); //发送ROM指令,跳过ROM匹配
Write_18b20(0X44); // 发送温度转换命令
for(i=0;i<50;i++) //延时1S,等转换完成
{
Delayms(20);
}
DS18B20_Init(); //初始化DS18B20
Write_18b20(0Xcc); //发送ROM指令,跳过ROM匹配
Write_18b20(0Xbe); //发送读取暂存器指令
Temp_L = Read_18b20(); //获得温度的低位
Temp_H = Read_18b20(); //获得温度的高位
if(Temp_H & 0x08) //判断温度的正负
{
Temp_H = ~Temp_H; //负温度。取反加1
Temp_L = ~Temp_L; //
SREG |= ~(1 << SREG_C); //清零进位位标志
Temp_L++; //温度低字节加1
if(SREG & (1 << SREG_C)) //有进位吗?
{
Temp_H++; //有进位,则温度高字节加1
}
}
tempint = ((Temp_H << 4) & 0x70) | (Temp_L >> 4); //获得温度的整数位
tempint1 = tempint / 1000; //千位
tempint2 = tempint % 1000 / 100; //百位
tempint3 = tempint % 100 / 10; //十位
tempint4 = tempint % 10; //个位
temppoint = Temp_L & 0x0f; //取出温度的小数位
temppoint = (temppoint * 625); //小数位乘以0.625得出温度的小数位值,在此扩大1000
//倍,得出温度的4位小数位,显示的时候加小数点
temppoint1 = temppoint / 1000; //千位
temppoint2 = temppoint % 1000 / 100; //百位
temppoint3 = temppoint % 100 / 10; //十位
temppoint4 = temppoint % 10; //个位
Usart_PutString("当前环境温度为:"); //发送温度值到上位机
if(!(tempint1)) //高位为零,则不显示
{
Usart_PutChar(' ');
if(!(tempint2))
{
Usart_PutChar(' ');
}
else
{
Usart_PutChar(tempint2 + 0x30);
}
if(!(tempint3))
{
Usart_PutChar(' ');
}
else
{
Usart_PutChar(tempint3 + 0x30);
}
//Usart_PutChar(tempint4 + 0x30);
}
else
{
Usart_PutChar(tempint1 + 0x30);
Usart_PutChar(tempint2 + 0x30);
Usart_PutChar(tempint3 + 0x30);
}
Usart_PutChar(tempint4 + 0x30);
Usart_PutChar('.'); //显示小数点
Usart_PutChar(temppoint1 + 0x30); //显示小数位
Usart_PutChar(temppoint2 + 0x30);
Usart_PutChar(temppoint3 + 0x30);
Usart_PutChar(temppoint4 + 0x30);
Usart_PutChar(' '); //不显示,空一格
Usart_PutChar('o'); //显示温度的符号。由于实在找不到温度那个再上面的小o,
Usart_PutChar('C'); //只好用普通的小写o来代替了。
Usart_PutChar(0x0D);
Usart_PutChar(0x0A); //结尾发送回车换行
sei(); //开中断
for(i=0;i<200;i++) //延时4S,再进行温度转换
{
Delayms(20);
}
}
}
//端口状态初始化设置函数
void Port_Init()
{
PORTD = 0X00; //USART的发送接收端口分别为PD0和PD1
DDRD |= (1 << 3); //PD0为接收端口,置为输入口;PD1为发送端口,置为输出口
PORTB = 0x00;
DDRB = 0xff;
}
void Port_DS18b20()
{
DDRC &= ~(1<<4); // 输入模式(上电时为高电平)
PORTC &= ~(1<<4); // 输出锁存器写0,以后不再更改
}
//USART寄存器配置函数
void Usart_Init()
{
UCSR1A = 0X00;
UCSR1C |= (1 << UCSZ11) | (1 << UCSZ10); //异步,数据格式8,N,1
UBRR1L = (F_CPU / BAUD / 16 - 1) % 256; //波特率设置
UBRR1H = (F_CPU / BAUD / 16 - 1) / 256;
UCSR1B |= (1 << RXCIE1) | (1 << RXEN1) | (1 << TXEN1); //发送使能
}
//字节发送函数
void Usart_PutChar(unsigned char cTXData)
{
while( !(UCSR1A & (1 << UDRE1)) ); //只有数据寄存器为空时才能发送数据
UDR1 = cTXData; //发送数据送USART I/O数据寄存器-UDR
}
//接收中断函数
ISR(USART1_RX_vect)
{
unsigned char Rev;
Rev = UDR1; //从USART I/O数据寄存器-UDR中读出数据
Usart_PutChar(Rev); //将接收到的数据发送
}
void Usart_PutString(unsigned char *pcString)
{
while (*pcString)
{
Usart_PutChar(*pcString++);
}
}
//DS18B20初始化
unsigned char DS18B20_Init()
{
SET_OUT; //PA2设置为输出口(相当于拉低数据线上的电平)
Delayus(490); //延时大于480us
SET_IN; //输入 释放数据线(相当于拉高数据线上的电平)
Delayus(68); //延时大于60US,
//while(DQ_IN); //可以用两个while()死循环来判断复位是否成功,当数据线被拉低,说明
//while(!(DQ_IN)); //18b20开始复位应答,当数据线变高,说明应答完毕
if(DQ_IN) //判断DS18B20是否拉低数据线
{
OK_Flag = 0; // 数据线是高?复位失败
}
else
{
OK_Flag = 1; // 数据线是低?复位成功
}
Delayus(422); //有复位应答信号后,应当再延时一段时间(480-68),以等待应答完毕
return OK_Flag; //返回复位标志
}
//从DS18B20读取一个字节数据
unsigned char Read_18b20()
{
unsigned char i;
unsigned char dat = 0; // dat用于存储读到的数据,先清零
for(i = 0;i < 8;i++) //共读8位数据,构成一个字节
{
SET_OUT; //定义为输出(拉低数据线)
Delayus(2); //拉低2微秒
SET_IN; //定义成输入,读入数据(同时也相当于拉高数据线)
Delayus(4); //延时
dat = dat >> 1; //数据右移,读顺序:先低后高
if(DQ_IN) //读数据,
{
dat |= 0x80; //如果是高,置1,右移数据
}
Delayus(62); //延时大于60us
}
return dat; //返回读到的1字节数据
}
//向DS18B20写1字节数据
void Write_18b20(unsigned char dat)
{
unsigned char i;
for(i = 0;i < 8;i++) //写8次,一次写1位,先写低字节
{
SET_OUT; //拉低数据线2us,开始写数据
Delayus(2); //
if(dat & 0x01) //写数据
{
SET_IN; //写1
}
else
{
SET_OUT; //写0
}
dat >>= 1; //数据右移1位,先写低位
Delayus(62); //延时大于60us
SET_IN; //拉高数据线
Delayus(2); //写两位数据的时间间隔
}
}
//us级别的延时函数
void Delayus(unsigned int lus)
{
while(lus--)
{
_delay_loop_2(4); //_delay_loop_2(1)是延时4个时钟周期,参数为3则延时12
//个时钟周期,本实验用12M晶体,则12个时钟周期为12/12=1us
}
}
//ms级别的延时函数
void Delayms(unsigned int lms)
{
while(lms--)
{
Delayus(1000); //延时1ms
}
}
|