⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 avr当中的一个简单的温度测试程序和学习avr中的一些笔记
💻 C
字号:
/***********************************************
****      AVR  DS18B20范例           ***
**** MCU: ATmega16                           ***
**** 作者:  maweili                        ***
**** 编译器:WINAVR                   ***
****                                         ***
****  	2008.11.27           ***
***********************************************/

#include <avr/io.h>        
#include <util/delay.h>
#include <avr/interrupt.h>   //中断函数头文件

//××××××××××××引脚宏定义×××××××××××××
//18B20定义
#define SET_DQ (PORTA) |= (1 << (PA2))      // 18b20 高电平
#define CLR_DQ (PORTA) &=~(1 << (PA2))      // 18b20 低电平
#define DQ_IN  (PINA) & (1<<(PA2))            // 18b20信号输入

#define SET_OUT (DDRA)|= (1<<(PA2))         //PA2定义成输出
#define SET_IN  (DDRA)&=~(1<<(PA2))         //PA2定义成输入



//常量声明
#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复位是否成功
		{
			PORTB = 0x01;
		}
		else
		{
			PORTB = 0x02;
		}
		*/
		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 << PD1);   //PD0为接收端口,置为输入口;PD1为发送端口,置为输出口

	PORTB = 0x00;
	DDRB = 0xff;	
}

void Port_DS18b20()
{
	DDRA &= ~(1 << PA2);   // 输入模式(上电时为高电平)
    PORTA &= ~(1 << PA2);  // 输出锁存器写0,以后不再更改
}

//USART寄存器配置函数
void Usart_Init()
{
	UCSRA = 0X00;	
	UCSRC |= (1<<URSEL) | (1 << UCSZ1) | (1 << UCSZ0);  //异步,数据格式8,N,1
	     //UCSRC寄存器与UBRRH寄存器共用相同的I/O地址,写 UCSRC 时, URSEL 应设置为 1。
	UBRRL = (F_CPU / BAUD / 16 - 1) % 256;    //波特率设置
	UBRRH = (F_CPU / BAUD / 16 - 1) / 256;		
	UCSRB |= (1 << RXCIE) | (1 << RXEN) | (1 << TXEN);    //发送使能
	
}

//字节发送函数
void Usart_PutChar(unsigned char cTXData)
{
	while( !(UCSRA & (1 << UDRE)) );  //只有数据寄存器为空时才能发送数据
	UDR = cTXData;	                 //发送数据送USART I/O数据寄存器-UDR
}

//接收中断函数
ISR(USART_RXC_vect )
{
	unsigned char Rev;
	Rev = UDR;              //从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(3);      //_delay_loop_2(1)是延时4个时钟周期,参数为3则延时12
		           //个时钟周期,本实验用12M晶体,则12个时钟周期为12/12=1us
    }
}

//ms级别的延时函数
void Delayms(unsigned int lms)
{
	while(lms--)
	{
		Delayus(1000);        //延时1ms
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -