仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
基于AVR单片机的汽车空调控制系统 摘要: AVR单片机功能强大,用AVR单片机开发各种控制系统只需很少的外部器件就可以实现强大的功能。本文介绍的就是利用Atmega16、CodeVisionAVR C开发环境、Proteus仿真软件开发汽车空调自动控制系统。
Atmega16是美国ATMEL公司的高档8位单片机,采用Flash存储器,可以擦写10000次以上、内部集成 、四通道PWM、集成8路10位精度ADC、片内经过标定的RC振荡器、采用精简指令集,具有32个通用工作寄存器,具有只需两个时钟周期的硬件乘法器,运算速度快等。由于其集成度高、处理速度快,使得利用AVR单片机进行系统开发只需很少(甚至没有)的外部器件即可实现强大的功能,逐渐在各种场合得到广泛应用,取代其它8位单片机。利用它来开发汽车空调控制系统,只需热电阻、液晶显示模块和一些继电器及其驱动芯片即可实现。 本系统可以分为五大部分:热电阻温度采集、运行状态显示、继电器控制、键盘输入、风向步进电机控制。 热电阻传感器以其温度特性稳定、测量精 
图1 Pt1000热电阻温度测量电路 度高的特点,在大型中央空调得到了广泛的应用。 采用Pt1000热电阻作为温度传感器的测量电路原理图如图1 所示。热电阻Rt与三个电阻接成电桥。当温度变化时,使得运算放大器的同相输入端的电位发生变化,经过运算放大器放大之后输入到Atmega16单片机进行AD转换。由于单片机采用5V电压作为ADC的参考电源,而电桥在温度变化为0~100°C时,输出电压范围为0~0.7V,所以确定运算放大电路的放大倍数为7,以获得最佳的测量结果。运算放大电路的电阻按以下公式确定:   取 。输出电压变化范围大致是0~5V。 由于ADC的转换精度为10,故当输入电压为5V时,其采样值为1023,根据电桥平衡原理,可得到以下公式: (1)
其中,N——ADC数据寄存器的值, U——电桥电源电压, ——Pt1000在0°C时的电阻1000 。
Pt1000热电阻的阻值按以下公式计算::  (2)
Rt——温度为t时铂热电阻的电阻值,Ω; t——温度,℃; ——Pt1000在0°C时的电阻1000 。
A——分度常数,A=0.0038623139728 B——分度常数,B=-0.00000065314932626 用Visual Basic.Net根据以上公式(1)、(2)生成用N来查找温度t的程序表格,其代码如下: Private Sub Pt1000() Me.Cursor = Cursors.WaitCursor txtTab.Clear() Dim U As Integer = 9 '电桥电源电压 '热电阻0度时的电阻值 Dim Pt1000_R0 As Integer = 1000 Dim n As Integer Dim sngT As Single Dim sngRt As Single txtTab.AppendText("const float Pt1000Tab[]={" & Chr(13) & Chr(10)) For n = 0 To 1023 sngRt = (10000 * n + 7161000 * U) / (7161 * U - 10 * n) sngT = (-const_A + Sqrt(const_A ^ 2 - 4 * const_B * (1 - sngRt / Pt1000_R0))) / (2 * const_B) If n < 1023 Then txtTab.AppendText(Format(Abs(sngT), "0.0") & ", /* " & n & " */") Else txtTab.AppendText(Format(Abs(sngT), "0.0") & " /* " & n & " */" & Chr(13) & Chr(10) & "};") End If If n Mod 5 = 0 Then txtTab.AppendText(Chr(13) & Chr(10)) End If Next txtTab.SelectAll() txtTab.Copy() Me.Cursor = Cursors.Default End Sub 生成的程序常数表格(1024个值)部分如下: const float Pt1000Tab[]={ 0.0, /* 0 */ 0.1, /* 1 */0.2, /* 2 */0.2, …… 63.4, /* 696 */63.5, /* 697 */ …… 99.3, /* 1022 */99.4 /* 1023 */ }; 2.2 运行状态显示 本系统采用一块16×4的字符型液晶模块,这种类型的LCD应用很广泛,其控制驱动主芯片为HD44780及其扩展驱动芯片HD44100(或兼容芯片),少量阻、容元件,结构件等装配在PCB板上而成。字符型液晶显示模块目前在国际上已经规范化,无论显示屏规格如何变化,其电特性和接口形式都是统一的。因此只要设计出一种型号的接口电路,在指令设置上稍加改动即可使用各种规格的字符型液晶显示模块。odeVisionAVR集成开发环境集成这种类型LCD的函数,可方便实现LCD的读写,其部分函数及功能简单介绍如下,更详细的资料可查阅各种文献。 函数原型:void lcd_init(unsigned char lcd_columns) 功能:初始化LCD模块,清屏并把显示坐标设定在0 列0 行。LCD模块的列必须指定(例如:16)。这时不显示光标。在使用其它高级LCD函数前,必须先调用此函数。 函数原型:void lcd_clear(void) 功能:清屏并把显示坐标设定在0 列0 行。 函数原型:void lcd_gotoxy(unsigned char x, unsigned char y) 功能:设定显示坐标在x 列y行。列、行。 函数原型:void lcd_putchar(char c) 功能:在当前坐标显示字符c 。 函数原型:void lcd_puts(char *str) 功能:在当前坐标显示SRAM 中的字符串str 。 函数原型:void lcd_putsf(char flash *str) 功能:在当前坐标显示FLASH 中的字符串str 。 在对LCD进行写入显示数据之前,需要对它进行初始化,设定显示参数。 #include <lcd.h> /*使用PORTB连接LCD模块*/ #asm .equ __lcd_port=0x18 ;PORTB #endasm void main(void){ //定义字符数组 uchar arr[5]; //初始化,指定列数为16 lcd_init(16); //设定显示坐标为(0,1) lcd_gotoxy(0,1); /*在(0,1)显示字符串,注意:此字符串存储在Flash只读存储器中*/ lcd_putsf("Run Mode:"); /*调用“浮点数转换成字符串”函数, 函数原型:void ftoa(float n, unsigned char decimals, char *str) data为浮点数*/ ftoa(data,1,arr); //设定显示坐标为(0,2) lcd_gotoxy(0,2); //显示RAM中字符串数组arr的内容 lcd_puts(arr); while(1); } Atmega16输出缓冲器具有对称的驱动特性,可以输出和吸收大电流,直接驱动LED,但是仍然不能直接驱动更大电流的器件,如继电器,所以必须接入较大功率的驱动器。常用的驱动方法有74系列功率集成电路驱动、MOC系列光耦合过零触发双向晶闸管驱动、固态继电器驱动等。 本系统采用ULN2003芯片来驱动继电器。其内部结构如图2所示。 ULN2003是达林顿阵列,是专门用来驱动继电器的芯片,甚至在芯片内部做了一个消线圈 
图2 ULN2003内部结构图 反电动势的二极管。ULN2003的输出端允许通过IC 电流200mA,饱和压降VCE 约1V左右,耐压BVCEO 约为36V。采用集电极开路输出,输出电流大,故可以直接驱动继电器或固体继电器(SSR)等外接控制器件,也可直接驱动低压灯泡,共可以驱动7路,减少了电路板的连线数量,成本较低,广泛应用于各种工控板,其驱动原理如图3所示。 
图3 驱动原理 压缩机离合器继电器采用RS触发器和ULN2003一起控制,这样做的好处是:当单片机受到外界干扰而不断复位或看门狗超时复位时,保证压缩机始终处于开启或关闭状态,有助于延长压缩机的寿命。 2.4键盘输入 本系统采用3×3矩阵式键盘。通过键盘可以控制系统工作方式(关闭、送风、制冷)、风向步进电机(水平送风、倾斜送风、扫风)、温度设定等。 键盘的行由PD0、PD1、PD2(使能内部上拉电阻)控制,而列则由PC3、PC4、PC5控制,如图4所示。采用程序扫描的方式识别键码,其工作过程如下: PORTC&=~0x20; if((PIND&0x07)!=0x07) {//……} 首先置PC5为“0”,再判断PD0、PD1、PD2是否都为“1”。如果全为“1”,则表明第3列无键按下,否则有键按下,进入消除抖动程序;再置PC4为“0”,再判断PD0、PD1、PD2是否都为“1”。如果全为“1”,则表明第2列无键按下,否则有键按下,进入消除抖动程序;再置PC3为“0”,再判断PD0、PD1、PD2是否都为“1”。如果全为“1”,则表明第1列无键按下,否则有键按下,进入消除抖动程序。 
图4 3×3矩阵式键盘
- ,消除抖动。当发现有键按下时,延时一段时间再判断键盘状态,若仍有键保持按下状态,则可以确定有键按下,否则认为是抖动。通过以下代码实现:
delay(); if((PIND&0x07)!=0x07) {//……}
- 判断键码。以下是识别为“Key2-3”( 第2行第3列)的程序代码,其它按健类似。
if((PIND&0x07)==0x05) { // Key 2-3 // uchar key_num[]="K23"; // 等待按键释放 while((PIND&0x07)==0x05); //判断换气风机是否在运行 if(ventilator_state==1) { ventilator_state=0; //关闭换气风机 stop_ventilator(); //在LCD上的(12,3)显示“OFF” lcd_gotoxy(12,3); lcd_putsf("OFF"); } else { ventilator_state=1; //开启换气风机 start_ventilator(); //在LCD上的(12,3)显示“Run” lcd_gotoxy(12,3); lcd_putsf("Run"); } return;//识别完毕,返回主程序 } 2.5 风向步进电机控制 Atmega16的定时器能够输出PWM,编程简单,精度高。编程让定时器2工作于相位可调模式,产生高精度的PWM波形输出,调节占空比,以达到控制步进电机不同转角的目的。初始化设置如下: ASSR=0x00; /* 相位可调PWM模式,比较匹配时清零OC2,计数为0xff时置位OC2 */ TCCR2=0x64; TCNT2=0x00; OCR2=0x00; TIMSK=0x80; //使能匹配中断 
图5 相位可调PWM 模式的时序图 
图6 水平送风模式下的PWM波形 
图6 倾斜送风模式下的PWM波形 3 仿真 Proteus是目前最好的模拟单片机及外围器件的仿真软件,可以仿真51系列、AVR,PIC等常用的MCU及其外围电路,如LED、LCD、RAM、ROM、键盘、马达、继电器、AD/DA、部分SPI器件、部分 器件、74系列、 COMS 4000系列芯片等。利用Proteus可以大大提高开发效率、降低投资,在没有硬件的情况下让开发人员能像Pspice仿真模拟/数字电路那样仿真MCU及外围电路。 Proteus提供的可调电阻是“十级可调”而不是“无级可调”,所以本系统采用三个可调电阻模拟Pt1000热电阻,以实现“粗调”、“中调”、“细调”,更真实反映热电阻阻值的细微变化。 
图7 换气风机、压缩机、蒸发器风机处于工作状态 
图8 LCD显示结果
4. 结语 本系统采用AVR单片机实现汽车空调的自动控制(双位控制),具有电路结构简单、分立元件少、系统界面友好、操作简单等优点,能满足一般精度要求的公交车空调的自动控制。
- /*****************************************************
- Project : 汽车空调控制系统
- Author : Benny
- Company : 509
- Comments:
- Chip type : ATmega16L
- Program type : Application
- Clock frequency : 8.000000 MHz
- Memory model : Small
- External SRAM size : 0
- Data Stack size : 256
- *****************************************************/
- #include <mega16.h>
- #include <stdlib.h>
- #include "Pt1000Tab.h"
- #include "inc.h"
- #asm
- .equ __lcd_port=0x18 ;PORTB
- #endasm
- #include <lcd.h>
- bit boolean;
- uchar ventilator_state;
- uchar fan;
- uchar blow;
- uchar run_mode;
- uchar temp;
- uchar setting_value;
- interrupt [TIM2_COMP] void timer2_comp_isr(void)
- {
- //产生PWM,控制步进电机
- if (fan==1)
- {
- OCR2=64;
- }
- else if(fan==2)
- {
- OCR2=128;
- }
- }
- #define FIRST_ADC_INPUT 0 //第一通道
- #define LAST_ADC_INPUT 1 //最后一通道 ,最大值为7,共8个通道
- unsigned int adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1];
- #define ADC_VREF_TYPE 0x40
- // ADC中断服务程序
- // 自动扫描模拟量输入端口,
- interrupt [ADC_INT] void adc_isr(void)
- {
- register static unsigned char input_index=0;
- // 读取转换结果
- adc_data[input_index]=ADCW;
- // 选择转换通道
- if (++input_index > (LAST_ADC_INPUT-FIRST_ADC_INPUT))
- input_index=0;
- ADMUX=(FIRST_ADC_INPUT|ADC_VREF_TYPE)+input_index;
- //启动AD转换
- ADCSRA|=0x40;
- }
- void main(void)
- {
- float current_temp;//保存当前温度
- // Port A 初始化
- // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
- // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
- PORTA=0x00;
- DDRA=0x00;
- // Port B 初始化
- // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
- // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
- PORTB=0x00;
- DDRB=0x00;
- // Port C 初始化
- // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
- // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
- PORTC=0x38;
- DDRC=0x38;
- // Port D 初始化
- // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
- // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
- PORTD=0x1f;
- DDRD=0xF8;
- //用T2产生PWM,控制风向步进电机
- // Timer/Counter 2 initialization
- // Clock source: System Clock
- // Clock value: Timer 2 Stopped
- // Mode: Normal top=FFh
- // OC2 output: Disconnected
- ASSR=0x00;
- TCCR2=0x64;
- TCNT2=0x00;
- OCR2=0x00;
- // Timer(s)/Counter(s) Interrupt(s) initialization
- TIMSK=0x80;
- // Analog Comparator initialization
- // Analog Comparator: Off
- // Analog Comparator Input Capture by Timer/Counter 1: Off
- ACSR=0x80;
- SFIOR=0x00;
- // ADC initialization
- // ADC Clock frequency: 125.000 kHz
- // ADC Voltage Reference: AVCC pin
- // ADC Auto Trigger Source: Free Running
- ADMUX=FIRST_ADC_INPUT|ADC_VREF_TYPE;
- ADCSRA=0xEE;
- SFIOR&=0x1F;
- // LCD module初始化
- lcd_init(16);
- // 开启全局中断
- #asm("sei")
- dis_character();
- setting_value=25;
- run_mode=0;
- ventilator_state=0;
- lcd_gotoxy(12,3);
- lcd_putsf("OFF");
- while (1)
- {
- scan_key();
- blow_mode();
- display();
- if(run_mode==2)
- {
- current_temp=Pt1000Tab[adc_data[0]];
- if (current_temp<setting_value)
- {
- stop_compressor();
- //lcd_gotoxy(10,1);
- //lcd_putsf("Blast");
- }
- else
- {
- start_compressor();
- //lcd_gotoxy(10,1);
- //lcd_putsf("Cool");
- }
-
- }
- }
- }
- void start_compressor(void){
- //Start
- PORTD|=0x18;
-
- PORTD&=~0x10;
-
- PORTD|=0x18;
- }
- void stop_compressor(void){
- //Stop
- PORTD|=0x18;
- PORTD&=~0x08;
- PORTD|=0x18;
- }
- void start_ventilator(void) {
- PORTD|=0x40;//换气风机运行
- }
- void stop_ventilator(void){
- PORTD&=~0x40;//换气风机停止
- }
- void start_evaporator_fan(void){
- PORTD|=0x20;//蒸发器风机运行
- }
- void stop_evaporator_fan(void){
- PORTD&=~0x20;//蒸发器风机停止
- }
- /*-----------------------------------------------键盘扫描-------------------------------------------
- -----------------------------------------------键盘扫描-------------------------------------------*/
- void scan_key(void){
- /*
- K11 K12 K13
- K21 K22 K23
- K31 K32 K33
- */
-
- //K13 K23 K33
- PORTC&=~0x20;
- if((PIND&0x07)!=0x07)
- {
- delay();
- if((PIND&0x07)!=0x07)
- {
- if((PIND&0x07)==0x06)
- { //Key 3-3
- //uchar key_num[]="K33";
- while((PIND&0x07)==0x06);
- switch(blow)
- {
- case 0:
- {
- blow=1;
- lcd_gotoxy(10,2);
- lcd_putsf("Mode0");
- break;
- }
- case 1:
- {
- blow=2;
- lcd_gotoxy(10,2);
- lcd_putsf("Mode1");
- break;
- }
- case 2:
- {
- blow=3;
- lcd_gotoxy(10,2);
- lcd_putsf("Mode2");
- break;
- }
- case 3:
- {
- blow=0;
- lcd_gotoxy(10,2);
- lcd_putsf("Mode3");
- break;
- }
- }
- return;
- }
- if((PIND&0x07)==0x05)
- { //Key 2-3
- //uchar key_num[]="K23";
- while((PIND&0x07)==0x05);
-
- if(ventilator_state==1)
- {
- ventilator_state=0;
- stop_ventilator();
- lcd_gotoxy(12,3);
- lcd_putsf("OFF");
- }
- else
- {
- ventilator_state=1;
- start_ventilator();
- lcd_gotoxy(12,3);
- lcd_putsf("Run");
- }
- return;
- }
- if((PIND&0x07)==0x03)
- { //Key 1-3
- //uchar key_num[]="K13";
- while((PIND&0x07)==0x03);
- switch(run_mode)
- {
- case 2:
- { //关闭模式
- stop_evaporator_fan();
- stop_compressor();
- lcd_gotoxy(10,1);
- lcd_putsf("OFF ");
- run_mode=0;
- break;
- }
- case 0:
- {
- //送风模式
- start_evaporator_fan();
- stop_compressor();
- lcd_gotoxy(10,1);
- lcd_putsf("Blast");
- run_mode=1;
- break;
- }
- case 1:
- {
- //制冷模式
- start_evaporator_fan();
- start_compressor();
- lcd_gotoxy(10,1);
- lcd_putsf("Cool ");
- run_mode=2;
- break;
- }
- }
-
- return;
- }
- }
- }
- PORTC|=0x20;
- //K12 K22 K32
- PORTC&=~0x10;
- if((PIND&0x07)!=0x07)
- {
- if((PIND&0x07)==0x06)
- { //Key 3-2
- //uchar key_num[]="K32";
- while((PIND&0x07)==0x06);
- return;
- }
- if((PIND&0x07)==0x05)
- { //Key 2-2
- //uchar key_num[]="K22";
- while((PIND&0x07)==0x05);
- if (setting_value<=18)
- {
- setting_value=18;
- }
- else
- {
- setting_value--;
- }
-
- return;
- }
- if((PIND&0x07)==0x03)
- { //Key 1-2
- //uchar key_num[]="K12";
- while((PIND&0x07)==0x03);
- if (setting_value>=28)
- {
- setting_value=28;
- }
- else
- {
- setting_value++;
- }
- return;
- }
- }
- PORTC|=0x10;
- //K11 K21 K31
- PORTC&=~0x08;
- if((PIND&0x07)!=0x07)
- {
- delay();
- if((PIND&0x07)!=0x07)
- {
- if((PIND&0x07)==0x06)
- { //Key 3-1
- //uchar key_num[]="K31";
- while((PIND&0x07)==0x06);
- return;
- }
- if((PIND&0x07)==0x05)
- { //Key 2-1
- //uchar key_num[]="K21";
- while((PIND&0x07)==0x05);
- return;
- }
- if((PIND&0x07)==0x03)
- { //Key 1-1
- //uchar key_num[]="K11";
- while((PIND&0x07)==0x03);
- return;
- }
- }
- }
- PORTC|=0x08;
- }
- void blow_mode(void){
- switch(blow)
- {
- case 0:
- {
- fan=0;
- break;
- }
- case 1:
- {
- fan=1;
- break;
- }
- case 2:
- {
- fan=2;
- break;
- }
- case 3:
- {
- temp++;
- if(temp==5)
- {
- boolean=~boolean;
- }
- if (boolean==1)
- {
- fan=1;
- }
- else
- {
- fan=2;
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
全部资料51hei下载地址:
基于AVR单片机的汽车空调控制系统资料.rar
(432.45 KB, 下载次数: 98)
|