嵌入式水温控制系统MC9S12DG128设计终.docx
《嵌入式水温控制系统MC9S12DG128设计终.docx》由会员分享,可在线阅读,更多相关《嵌入式水温控制系统MC9S12DG128设计终.docx(33页珍藏版)》请在冰豆网上搜索。
![嵌入式水温控制系统MC9S12DG128设计终.docx](https://file1.bdocx.com/fileroot1/2023-1/8/67465ca6-11c1-45c6-a250-a2586bb53c64/67465ca6-11c1-45c6-a250-a2586bb53c641.gif)
嵌入式水温控制系统MC9S12DG128设计终
嵌入式系统设计性实验报告
水温控制系统
系别:
控制工程学院
专业:
自动化
学号:
姓名:
指导老师:
孙文义
2012年6月6日
水温控制系统
一、任务
设计并制作一个水温自动控制系统,控制对象为1升净水,容器为搪瓷器皿。
水温可以在一定范围内由人工设定,并能在环境温度降低时实现自动控制,以保持设定的温度基本不变。
二、要求
(1)温度设定范围为40~90℃,最小区分度为1℃,标定温度≤1℃。
(2)环境温度降低时(例如用电风扇降温)温度控制的静态误差≤1℃。
(3)用十进制数码管显示水的实际温度保留一位小数。
(4)采用适当的控制方法(如数字PID),当设定温度突变(由40℃提高到60℃)时,减小系统的调节时间和超调量。
(5)温度控制的静态误差≤0.2℃。
(6)从串口输出水温随时间变化的数值。
实验要求:
1、写出设计报告(要求见附件)
2、键盘采用4*4扫描键盘用于设定温度值
3、数码管采用动态扫描方式
4、采用PWM工程DA转换器控制电热丝加热
5、串口每秒钟向计算机发送一次温度值
6、用小灯模拟加热强度,将DA输出平均分为8段,处于第一段时最低位灯亮
处于第二段时,最低位两个小灯亮,处于第8段时所有小灯都亮。
7、采用内部10位AD转换方式测量温度值,用电位器模拟温度变化
嵌入式系统设计性实验报告
摘要:
该实验设计基于飞思卡尔MC9S12DG128开发板平台,用电位器模拟水温,采用单片机内部10位AD转化器,以及PWM模块对温度进行控制,该水温控制系统是一个典型的检测、控制系统,他要求系统完成模拟量输入完成、信号处理运算、输出显示的全部过程。
本设计实现了水温的智能控制和人机交互接口以及串行通信。
关键字:
水温控制、飞思卡尔MC9S12DG128单片机、PID控制、PWM控制输出
前言:
具体实验任务描述
1.最小系统电路包括电源电路、PLL电路、复位电路、晶振电路BDM调试接口、串行通信电路等,是单片机能工作的前提。
2.键盘采用4*4扫描键盘用于设定温度值,按A键进入设定模式,按B键进行确定。
0-9十个数字用于输入设定的数字。
3.数码管采用动态扫描方式,显示设定的温度值和实时的温度值。
数码管驱动采用三极管放大电流,为八个二极管提供电流
4.采用PWM工程DA转换器控制电热丝加热,PWM输出不同的高低电平,控制电热丝的通断
5.采用SCI模块每秒钟向计算机发送一次温度值
6.用小灯模拟加热强度,将DA输出平均分为8段,处于第一段时最低位灯亮处于第二段最低位两个小灯亮,处于第8段时所有小灯都亮。
7.用电位器模拟温度变化,采用内部10位AD转换方式测量温度值。
正文
一、系统设计的功能
画出系统功能框图,说明每个功能模块的作用。
图1.水温控制系统功能框图
二、硬件设计原理及内容
画出实验电路原理图,说明每个硬件模块的工作原理与作用。
原理图模块电路及各部分功能:
1.电源电路
HCS12MCU的芯片内部使用3V电压,I/O端口和外部供电电压为5V,电源电路中的C3和C4构成滤波电路,可以改善系统的电磁兼容性,降低电源波动对系统的影响,增强电路工作稳定性。
LED0为电源指示灯。
2.PLL电路
PLL电路兼有频率放大和信号提纯的功能,系统可以以较低的外部时钟信号获得较高的工作频率,以降低因高速开关时钟过造成的高频噪声。
3.晶振电路
晶振电路为MCU提供工作时钟频率,器件所有的时钟信号都来自EXTAL引脚输入的时钟
4.BDM接口电路和复位电路
BDM调试方式为开发人员提供了底层的调试手段,开发人员可通过它初次向目标板下载程序,同时也可通过BDM调试器对目标板MCU的Flash存储器进行写入、擦除等操作。
用户也可通过它进行应用程序的下载和在线更新,在线动态调试和编程,读取CPU各个寄存器的内容,MCU内部资源的配置与修复,程序的加密处理等操作。
MCU在响应各种外部或侦测到得内部系统故障时可进行系统复位,复位时,将寄存器和控制位设置成已知的其实默认值。
复位的用途是错误恢复,即当MCU检测到内部故障时,它尝试回到一个已知的、明确的状态而从故障中恢复。
5.串行通信接口SCI
串行通信实现MCU与PC之间进行通信,接收时,把外部数据的单线输入的数据变成一个字节的并行数据送入MCU内部,发送时,把需要发送的一个字节的并行数据转换为单线输出。
6键盘输入电路
矩阵键盘用以控制设置系统的温度值。
P端口的低四位0-3设置为输出,高四位4-7设置为输入,(即DDRP=0xOF)。
通过PTP的低四位逐行输出低电平,同时读取PTP的高四位,将低四位的输出状态与读取的高四位的状态相“与”,然后查询保存在RAM中的表就能判断被按下键的位置。
7数码管显示电路
.数码管用以显示检测到的温度实际值(试验中用电位器AD模拟温度变化)。
在设定状态时显示设定值。
片选端接T端口低四位,数据端接A端口。
采用三极管放大电路,驱动数码管。
3、系统软件设计流程
画出系统软件流程图
图三程序流程图
4、调试过程及数据
在开始做这个设计的时候,先是把系统的每一部分都分成不同模块,每一个模块先单独作为一个工程建立,每一个模块调试成功之后才将各部分组合在一起,最终调试成为一个系统的。
系统的模块分为:
SCI串行口输入输出模块、LED数码管显示模块、KB键盘输入模块,AD转换输入模块,PWM模块。
模块的调试过程:
1.SCI串行口调试使用方法:
编程:
1.将SCI的初始化,设置波特率、接收发送数据的格式,接收发送的方式。
2.编写发送函数和接收函数,接收以中断方式实现,故还要编写中断接收函数。
调试:
编译通过后,在串口调试助手里输入字符,如果成功显示我们在键盘上输入的字符,则说明SCI串行口模块可以调用,如果显示不成功则需要继续对程序进行修改和编译。
在串行口这里我遇到的问题是:
a、键盘输入的字符不在串口助手显示。
解决办法:
不能显示的原因是自己对串口发送和接收的程序没能充分理解,不知道函数间数值是如何传递的,经过对发送程序和接收语句的一条条分析,得以理解,修改主程序,编译通过。
另外实验板的晶振16M,但是单片机MC9S12DG128中未启用锁相环,故单片机的内部总线实际上只有16M/2.所以在串行口波特率要求9600时,需要在程序的串口初始化中将SCI0BDL=0X80改为SCI0BDL=0X34。
2.LED数码管调试使用方法:
编程:
首先将LED编程初始化,然后编译共阳数码管的段选数表,位选数表。
最后编写LED显示一个数和LED显示4个数的函数。
接线:
1-12接口分别对应接e、d、h、c、g、cs0、b、cs1、cs2、fa、cs3。
调试:
在数码管的测试主函数中编程保证数码管能够显示我们输入的静态数字。
比如我们在主函数中,让数码管显示“0123”,4位数码能够正常显示0123,则说明数码管模块中的函数可以被调用,否则需要继续对程序进行修改和编译。
在数码管这里我遇到的问题是:
a、数码管不显示。
原因是实验板上的数码管是共阳的,而教材上的程序是针对共阴数码的。
重新编写显示码表Dtable[10],问题得以解决。
后来发现只要在Dtable[]前加取反符号即~Dtable[]就可以了,省去了很多麻烦。
b、数码管正常显示数字但四个数码管都显示小数点。
原因及解决办法:
自己的段选数表编错了,在显示4个数的函数中直接把段选数表赋给A端口。
修改段选数表,在显示4个数的函数中判断是否为第三个数码管,若是才点亮小数点,若不是,只显示数。
3.KB键盘输入模块
编程:
首先键盘初始化,再要找到按键的位置,其次要通过多次扫描去除抖动,还要将键值转换为设定值,并能读取定义值,最后编写一个设定函数。
接线:
P端口的高四位接键盘列四个接口,低四位接行四个接口
调试:
在键盘测试主函数中编程保证输入的数字能在数码管显示,按A键进入设定模式,按B键确定。
如果能实现那么说明键盘编写的函数能被主函数调用。
在键盘这里我遇到的问题是:
a、在键盘输入数字,在数码管显示的却是乱码
原因及解决办法:
问题在扫描的键值Keynum是字符型数据,直接调用LEDShow(1,Keynum),所以会显示乱码,解决办法是Keynum转换为数字即Keynum—‘0’,在调用LEDshow1(1,Keynum),显示正常。
b、键盘输入的数字,在数码管上显示一位数字,但是在超级终端上显示一连串一摸一样的字符。
原因及解决办法:
键盘的扫描速度比串行口的通讯速度快,以至于在串行口检测数据的时候,键盘已经扫描多次,所以重复发送。
后来在程序中增加了一个延时程序,让扫描键盘之后等待一段时间,此时间比串口扫描时间略长,再扫描,最终达到按一下矩阵键盘,数码管显示数字,超级终端只出现一个数字的结果。
4.AD转换输入模块
编程:
首先将AD转换器初始化,编写一个通道的函数、AD中断函数,中值滤波、均值滤波函数。
调试:
在编译通过AD转换程序后,联系数码管显示模块,用一个可变电阻(电位器)的检测采样,用单片机的AD转换通道AN06输入采样信号,将其转化为0~100可变数字,用以模拟温度0~100度的变化,并在数码管上显示。
在AD转换这里我遇到的问题是:
a、数码管显示的数字没有小数点
原因及解决办法:
为了显示小数点,自己通过在数码管的程序中单独加入了一个数组DATA2,这个数组中的每一位数字“0123456789”中的编码都带有小数点,在显示程序调用时,让数码管的从右至左第二位数码管单独调用此数组。
而其他的几个数码管在调用显示数字时依然用DATA1I即这个数组中的每一位数字“0123456789”中的编码没有小数点。
5.控制输出模块
编程:
编写一个PID控制函数、控制PWM输出函数,标度转换函数、将结果分解显示函数
B口模拟加热强度函数
在控制输出这里我遇到的问题是
a、温度设定超过76.5摄氏度时,只能加热到76.5摄氏度
此问题未能解决
5、实验结果与心得
实验的最终结果:
1.实现了用4*4扫描键盘设定温度值,按A键进入设定模式,可以自右向左设定温度值,按B键进行设定。
实现了串口每秒钟向计算机发送一次温度值。
2.实现了采用PWM工程DA转换器控制电热丝加热,3.实现了用小灯模拟加热强度,将DA输出平均分为8段,处于第一段时最低位灯亮处于第二段时,最低位两个小灯亮,处于第8段时所有小灯都亮的要求。
4.实现了数码管实时显示温度值。
5.实现了采用内部10位AD转换方式测量温度值,用电位器模拟温度变化
实验心得:
到此为止,本学期嵌入式系统的实验基本就结束了。
水温控制实验做完我觉得收获了很多。
我了解了嵌入式系统开发过程,编写了对我来说到目前为止最复杂的程序。
在此之前,我们并没有了解过类似的知识,也并没有过类似的实验经验。
谈一下我们的主要收获。
在实验编程的过程中,我们遇到了很多的问题。
从刚开始完全不知从何入手,到用codewarrior编写简单函数,发现了很多问题,我C语言学的不扎实,编写程序经常丢三落四,没有条理。
但是经过多次修改编译成功了。
后来开始编写复杂函数,在编译的过程中,开始没有思路,PID函数完全不知如何编写,后来经过上网查询和参考老师给的程序,学会了PID控制的编程。
6、参考资料
学出实验过程中用到的参考资料,要求写出参考资料的来源,页码和参考内容
嵌入式系统——使用HCS12微控制器的设计与应用.王宜怀P119串行口处理相关函数
嵌入式系统——使用HCS12微控制器的设计与应用.王宜怀P134键盘处理相关函数
嵌入式系统——使用HCS12微控制器的设计与应用.王宜怀P140LED数码管相关函数
嵌入式系统——使用HCS12微控制器的设计与应用.王宜怀P202A/D转换相关函数
基于HCS12的嵌入式系统设计第七章脉宽调制模块及其应用实例
7、附录
一、最小系统PCB板
最小系统3D板
二、原理图
三、源程序
#include
/*commondefinesandmacros*/
#include/*derivative-specificdefinitions*/
#defineBUS_CLOCK8000000
//总线频率
#defineBAUD9600
#defineReSendStatusRSCI0SR1
#defineReTestBit5
#defineSendTestBit7
#defineReSendDataRSCI0DRL
#defineKB_PPTP//键盘接在H口上
#defineKB_DDDRP//相应的方向寄存器
#defineKB_PEPERP//相应的上啦下拉电阻允许寄存器
#defineKB_PSPPSP//相应的极性选择寄存器
#defineKB_IEPIEP//相应的中断允许寄存器
#defineKB_IFPIFP//相应的中断标志寄存器
#defineEnableSCIReIntSCI0CR2|=0X20//开放SCI0接受中断
#defineDisableSCIReIntSCI0CR2&=0XDF//禁止SCI0接受中断
#defineSCFBit7//转换完成标志位
#defineATDCTL2ATD0CTL2
#defineATDCTL3ATD0CTL3
#defineATDCTL4ATD0CTL4
#defineATDCTL5ATD0CTL5
#defineATDSTAT0ATD0STAT0
#defineATDDR0ATD0DR0
#definekp100
#defineki1
#definekd100
unsignedcharLEDbuf[4]={'0','0','0','0'};
//数码管显示数组
unsignedcharFlag_Send,Flag_ADC;
unsignedintAD_wData;
unsignedintTemperature_Set;
/*****************************************/
/*延迟*/
/****************************************/
voidDelay(unsignedintk)
{
unsignedintu;
for(u=0;u}
/*************************************/
/*初始化SCI*/
/************************************/
voidSCIIint(void)
{
SCI0BD=BUS_CLOCK/16/BAUD;//设置SCI0波特率为9600
SCI0CR1=0x00;//设置SCI0为正常模式,八位数据位,无奇偶校验
SCI0CR2=0x2c;//允许接收和发送数据,允许接收中断功能
}
/***********************************/
/*串口发送函数一个字节*/
/***********************************/
voidSCISend1(unsignedchara)
{
while
(1)
{
//若SCI0SR1第七位为一,条件成立,此时发送数据寄存器空
if((ReSendStatusR&(1<=0)
{
ReSendDataR=a;
break;
}
}
}
/*************************************/
/*串口接收函数一个字节*/
/*************************************/
unsignedcharSCIRe1(unsignedchar*p)
{
unsignedintk;
unsignedchari;
for(k=0;k<0xfbbb;k++)
{
//若SCI0SR1第五位为一,条件成立,此时接收数据寄存器数据可用
if((ReSendStatusR&(1<=0)
{
i=ReSendDataR;
*p=0x00;
break;
}
if(k>=0xfbbb)
{
i=0xff;
*p=0x01;//返回出错标志
}
returni;
}
}
/**************************************/
/*串口发送N字节函数*/
/**************************************/
voidSCISendN(unsignedcharn,unsignedcharch[])
{
unsignedchari;
for(i=0;i{
SCISend1(ch[i]);
}
}
/**************************************/
/*串行接收N字节*/
/*************************************/
unsignedcharSCIReN(unsignedcharn,unsignedcharch[]){
unsignedcharm;
unsignedcharfp;
m=0;
while(mch[m]=SCIRe1(&fp);
if(fp==1){
return1;
m++;
}
return0;
}
}
/************************************/
/*中断接收函数*/
/***********************************/
voidinterruptISR_Receive(void)
{
unsignedchari;
unsignedcharSerialBuff[1];
i=SCIReN(1,SerialBuff);
SCISendN(1,SerialBuff);
}
/***************************************/
/*数码管显示表片选表*/
/***************************************/
constunsignedcharDtable[11]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};
constunsignedcharCStable[4]={0xf7,0xfb,0xfd,0xfe};
/************************************/
/*LED初始化*/
/************************************/
voidLEDInit(void)
{
DDRA=0XFF;//定义A口为输出
DDRT=0X0F;//T口低四位为输出
}
/************************************/
/*LED显示一个数*/
/************************************/
voidLEDShow1(unsignedchari,unsignedcharc)
{
PTT=CStable[i];
if(i==2)
{
PORTA=(~Dtable[c])&0x7f;//若为第二个数码管点亮小数点
}else{
PORTA=~Dtable[c];
}
}
/****************************************/
/*显示4个十进制数*/
/***************************************/
voidLEDShow(unsignedchar*buf)
{
unsignedchari,c;
unsignedintj;
for(i=0;i<=3;i++)
{
c=buf[i]-'0';
LEDShow1(3-i,c);
for(j=0;j<=100;j++);
}
}
/**************************************/
/*键盘定义表*/
/**************************************/
constunsignedcharKB_Table[33]=
{
0xee,'1',0xde,'2',0xbe,'3',0x7e,'4',
0xed,'5',0xdd,'6',0xbd,'7',0x7d,'8',
0xeb,'9',0xdb,'0',0xbb,'A',0x7b,'B',
0xe7,'C',0xd7,'D',0xb7,'E',0x77,'F',
0x00
};
/*****************************************/
/*键盘初始化*/
/****************************************/
voidKB_Init(void)
{
KB_P=0x00;//复位KB_P
KB_D=0x0f;//定义7-4为输入3-0为输出
KB_PE=0xf0;//定义KB_P.7-4允许上拉或下拉
KB_PS=0x00;//定义KB_P.7-4上拉电阻,并且由下降沿产生中断
KB_IE=0x00;//定义KB_P.7-4输入引脚禁止中断
KB_IF=0xff;//清除键盘中断标志位(写1清除)
}
/****************************************/
/*扫描读取键值函数*/
/*功能:
扫描一次4乘4键盘*/
/*返回扫描到的键值*/
/***************************************/
unsignedcharKB_Scan1(void)
{
unsignedcharline,i,temp;//line低四位值决定扫描的行高四位的值始终为F
line=0xfe;//使第一根行线为零(低电平)
for(i=1;i<=4;i++)//最多将扫描4根行线
{
//以上三行将当前扫描的一行输出低电平
temp=KB_P;
temp|=0