专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

AVR单片机温度计

作者:未知   来源:不详   点击数:  更新时间:2014年06月28日   【字体:

 自带吐槽功能。

 
 
 
估计每年都会有好多苦逼毕业设计是做这个吧,送上源代码:
 
 
 
#include
#include
#include <1602.h>
#include
 
unsigned char i;
int temp;
 
void timer0_init()
{
 DDRD|=0x30;       //PortD=00110000,OC1B(PortD4)引脚输出
 TCCR1A|=0x63;            //01(匹配时电平取反)10(匹配时清零,TOP时置位)0011(15模式)
 TCCR1B|=0x1A;     //00011(15模式) 010(8分频)
 OCR1A=2499;     //TOP值(OCR1A):1MHZ/目标50HZ/8分频-1=2499
 OCR1B=63;     //匹配值:占空比20%,则=TOP值*0.2    舵机:2.5% ~ 12.5% : 63~300
}
 
void SetMotor(int tmp)
{
 int i;
 int start=130;
 int end=300;    //该模块只响应 -5 ~ 45 摄氏度的范围 63
 tmp=tmp+5-2;     //变成0~50度范围,偏移2度
 i=(end-start)/50;   //求出1摄氏度等于舵机转多少角度
      
 if(tmp>48)     //输出改变舵机角度
 {  OCR1B=start;  }
 else if(tmp<-2)
 {  OCR1B=end;  }
 else
 {  OCR1B=end-i*tmp; }
  
 
 
 
int main(void)  
{    
  lcd_init();                         //lcd初始化           
  lcd_dictate(1);                         //清屏,光标回位  
 timer0_init();
 
 lcd_gotoxy(0,0);
 lcd_putsf("Checking Sensor",15);  //温度传感器检测
    gettemperature(); 
 SetMotor(0);
 _delay_ms(500);_delay_ms(500);
 SetMotor(52);
 _delay_ms(500);_delay_ms(500);
 lcd_dictate(1); 
 
 
 
  while(1)   
  { 
  lcd_gotoxy(0,0);
  lcd_putsf("Temperature:",12);
  lcd_gotoxy(15,0);
  lcd_putsf("C",1);
        temp=gettemperature();
  if(negative) {lcd_gotoxy(12,0);lcd_putsf("-",1);}
 
   lcd_gotoxy(13,0);
  lcd_byte(integer);
  
  if(integer>=35&&!negative) {lcd_gotoxy(0,1);lcd_putsf("Tips:Go Naked...",16);}
  else if(integer>=29&&!negative) {lcd_gotoxy(0,1);lcd_putsf("Tips:Buy Aircon!",16);}
  else if(integer>=20&&!negative) {lcd_gotoxy(0,1);lcd_putsf("Tips:Go Travel!!",16);}
  else if(integer>=10&&!negative) {lcd_gotoxy(0,1);lcd_putsf("Tips:Let's BBQ!",15);}
  else{lcd_gotoxy(0,1);lcd_putsf("Tips:Hibernate..",16);}
 
  SetMotor(temp);
     }  
}   
 
 
 
=================分割线==================
 
#ifndef _1602lcd_INCLUDED_             //如果原来没有宏定义本名字就...
#define _1602lcd_INCLUDED_             //定义一下,防止多次被头文件包含
#include                 //本例使用7线连接(也可以使用6线,但是没有读"忙"功能,不推荐)
 
//写LCD,  datas是数据,高4位有效,rs决定datas是显示还是指令,read_lcd决定是否需要读取忙标志BF
void lcd_h(unsigned char datas,unsigned char rs,unsigned char read_lcd)
{  
  DDRA=0xFF;                    //RS/RW/E设置为输出
 
 if(read_lcd)
    {       
       DDRB=0x00;              //先把4个数据口设置为输入
  PORTA&=~(1<<0);    //RS=0;
       PORTA|=(1<<1);          //RW=1 读BF
       PORTA|=(1<<2);    //E=1
       _delay_ms(10);          //等待,直到DB7=0,这里不等了 
    }
 if(rs==1)     //RS=rs,写指令或者数据
 {
  PORTA|=(1<<0);
 }else{
  PORTA&=~(1<<0);
 }
 PORTA&=~(1<<1);    //RW=0,写
 DDRB=0xFF;               //把4个数据口设置为输出
 
   PORTA|=(1<<2);     //E=1
   if(datas&128) PORTB|=(1<<3); else PORTB&=~(1<<3);
   if(datas&64)  PORTB|=(1<<2); else PORTB&=~(1<<2);
   if(datas&32)  PORTB|=(1<<1); else PORTB&=~(1<<1);
   if(datas&16)  PORTB|=(1<<0); else PORTB&=~(1<<0);
   PORTA&=~(1<<2);    //E=0;LCD在E下降沿时对RS与DB4-DB7进行取样
 
void lcd_dictate(unsigned char data)  //写指令函数
  lcd_h(data,0,1);                    //输出高4位 
  lcd_h(data*16,0,1);                 //输出低4位
 
void lcd_putchar(unsigned char data)  //写显示函数
{  
  lcd_h(data,1,1);                    //输出高4位 
  lcd_h(data*16,1,1);                 //输出低4位
 
//初始化函数
void lcd_init(void)
{   
  _delay_ms(40);
  lcd_h(48,0,0); _delay_ms(12);         //这3条是初始化语句
  lcd_h(48,0,0); _delay_ms(10); 
  lcd_h(48,0,0);              
  lcd_h(32,0,1);                      //使能4位数据线
  lcd_dictate(40);                    //显示参数设定
  lcd_dictate(12);                    //显示参数设定
}  
  
//列/行定位函数,最开头的地址是0列0行
void lcd_gotoxy(unsigned char x, unsigned char y)  //列/行定位函数
{      
  if(x<=19 && y<=3)                    //防止输入的数据不正确
    {                                
      if(y==0) lcd_dictate(x+128);     //第0行的地址是从128开始
      if(y==1) lcd_dictate(x+192);     //第1行......
      if(y==2) lcd_dictate(x+148);
      if(y==3) lcd_dictate(x+212);
    }
}     
 
void lcd_hex(unsigned char byte_data)                //以十六进制显示一个字节变量
{
  unsigned char data; 
  
  data=byte_data>>4;                             //求高4位
  if(data<10) data+=48; else data+=55;    //转化为ASCII值
  lcd_putchar(data);                             //显示
  
  data=byte_data&15;                             //求低4位
  if(data<10) data+=48; else data+=55;    //转化为ASCII值
  lcd_putchar(data);                             //显示
}  
 
void lcd_byte(unsigned char byte_data)                //以十进制显示一个字节变量
{
  unsigned char data; 
  
  data=byte_data/100;                            //求百位数
  lcd_putchar(data+48);                          //转化为ASCII值再显示
  
  data=byte_data/10;                          //求十位数
  lcd_putchar(data+48);                          //转化为ASCII值再显示
  
  data=byte_data;                             //求个位数
  lcd_putchar(data+48);                          //转化为ASCII再再显示
}  
 
void lcd_putsf(flash unsigned char *string , unsigned char n) //显示FLASH里面的字符串
{        
  unsigned char i=0;
  while(i
       {  
         lcd_putchar( string[ i ] ) ;                 //顺序显示字符
         i++;                         
       }
}
#endif
 
=================分割线==================
 
//monobus.h文件,用于操作DS18B20/DS2401等单总线器件,本单片机频率有点快,//delay_us(480)代表延时480微妙,实际要用2条指令达到480us,其他单片机延时准确的话可以用一条
 
#define monobus_1  DDRC&=~(1<<1)     //设置单片机IO为输入,由于总线存在上拉电阻,所以此时电平是1
#define monobus_0  DDRC|=(1<<1)     //设置单片机IO为输出,配合默认的 PORTC.0=0 则输出0电平
#define monobus_in PINC&(1<<1)       //检测总线(从机)的电平状态
#include
 
unsigned char negative,integer;    //求出温度的符号,整数部分
 
 
void monobus_init(void)          //复位,不检测从机设备是否存在(只要没有虚焊就肯定存在的) 
{
   monobus_0;
   //delay_us(480);
   _delay_us(480);
   _delay_us(480);
   monobus_1;  
 while(monobus_in);
 while(!monobus_in);
   //delay_us(480);
   _delay_us(480);
   _delay_us(480);
 
}
 
void write_monobus(unsigned char data)     //向单总线的从机写入数据(先写低位再写高位,与SPI相反)
   unsigned char n=1; 
   while(n)
   {
     monobus_0;
     //delay_us(2);                          //拉低总线1-3us,通知从机准备收发数据
  _delay_us(4);
     if(data&n) monobus_1; else monobus_0;   //向总线写数据的某一位(1或者0)
     //delay_us(75);                         //等待90us,保证从机有足够的时间进行采样(24-210us)
  _delay_us(150);
     monobus_1;                              //释放总线    
     //delay_us(2);                          //释放总线时间要大于1us  
  _delay_us(3);
     n<<=1;
   }
 
unsigned char read_monobus(void)             //读单总线的从机数据(先传输低位后传输高位,与SPI相反)
{
   unsigned char data_18b20=0;  
   unsigned char n=1;
   while(n)
   {
     monobus_0;
     //delay_us(2);                            //拉低总线1-3us,通知从机准备收发数据
  _delay_us(3);
     monobus_1;                               //释放总线
     //delay_us(5);                            //从机在1-25us内会向总线输出数据的某一位(1或者0)
  _delay_us(10);
     if(monobus_in)
   data_18b20+=n;              //读取总线数据
     //delay_us(55);                           //等待从机释放总线
  _delay_us(110);
     n<<=1;           //挪够8位则等于清零
   } 
   return data_18b20;
}
 
int gettemperature(void)
{
 unsigned char data_L,data_H;
 int  data_T;
 float data_D;
  monobus_init();                 //单总线复位
  write_monobus(0xCC);            //跳过ID码匹配,适用于一个DS18B20     
    write_monobus(0x44);            //启动温度转换
         
  _delay_ms(500);                 //等待转换
 _delay_ms(500);
 
    monobus_init();                 //单总线复位
    write_monobus(0xCC);            //跳过ID码匹配
   write_monobus(0xBE);            //通知DS18B20,准备读数据
 
   data_L=read_monobus();          //读取第一个数据(温度低字节)
   data_H=read_monobus();          //读取第二个数据(温度高字节)
                   //可以继续读取第三个到第九个RAM数据
    //data_T=data_H*256+data_L;       //合并后得到原始温度数据
   
 if(data_H>15) negative=1;     //data_H的4到7位为正负符,例如温度为负时是1111 1xxx,为正是0000 0xxx
            //data_L的8位和data_H的前3位共同表达温度,可以表达-55 ~ 125,
 if(!negative)        //为正温度   //负数用补码表达, 反回来
 {
  data_T=data_H*256+data_L;
  data_T/=16;
 } else {
  data_T=~data_H;
  data_T<<=8;
  data_T=data_T|~data_L;
  data_T=data_T+1;
  data_D=data_T*0.0625;
  data_T=data_D*10+0.5;
 }
 integer=data_T;
 
 return data_T;        //没要求则返回整数部分
}
 
 
 
=================分割线==================
关闭窗口

相关文章