STC12C5410AD课程设计
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
单片机原理及应用课程设计
单片机学习及其Proteus仿真2008-08-23 22:51:49 阅读1220 评论0 字号:大中小
1、摘要:
单片机自70年代问世以来得到蓬勃发展,目前单片机功能正日渐完善:单片机集成越来越多资源,内部存储资源日益丰富,用户不需要扩充资源就可以完成项目开发,不仅是开发简单,产品小巧美观,同时抗干扰能力加强,系统也更加稳定,使得它更加适合工业控制领域,具有更加广阔的市场前景;提供在线编程能力,加速了产品的开发进程,为企业产品上市赢得宝贵时间。
此外单片机具有性能高、速度快、体积小、价格低、稳定可靠、应用广泛、通用性强等突出优点。
单片机的设计目标主要是增强“控制”能力,满足实时控制(就是快速反应) 的需要。
因此,掌握单片机的基础和实际应用对电子信息专业从业者来说意义重大。
本文的主要内容是掌握各种单片机的结构、接口、片上外设的特点,并用STC12C5410AD单片机的片上资源设计出适当的最小系统;并利用自行制作的单片机最小系统,完成一个简单应用(量程自动转换的电压表)的设计与软件及硬件设计制作,让读者掌握数字单片机最小系统的设计及单片机系统的应用方法。
关键字:单片机、最小系统、量程自动转换、电压、STC12C5410AD
2、设计要求
a)、掌握各种单片机结构、接口、外设的特性原理,完成最小系统设计。
b)、掌握单片机的开发过程及方法,完成最小系统的制作调试;设计要求。
✧使用STC12C5410AD CPU
✧使用STC232E建立ISP/IAP/RS23C接口
✧使用93C46扩展EEPROM
✧ISP/IAP/RS232C接口:STC232E
✧使用HT1380建立实时时钟
✧设计4×4键盘接口
✧设计6位LED显示器
✧自制+5V整流稳压电源
c)、利用自制的单片机最小系统,完成至少一种应用的设计。
d)、完成单片机最小系统应用系统的制作调试。
e)、通过课程设计报告的写作,锻炼科技论文报告的写作能力。
3、方案论证和总体设计
3.1、主要芯片资源简述
3.1.1、STC12C5410AD单片机
该单片机是宏晶科技生产的单时钟/机器周期(1T)的单片机,是高速/低功耗/超强抗干扰的新一代8051单片机,指令代码完全兼容传统8051,但速度快8-12倍,内部集成MAX810专用复位电路。
4路PWM,8路高速10位A/D转换,由于该芯片内部集成A/D转换和PWM,因此需要很少的外围电路即可实现A/D和D/A转换,从而使得最小系统的硬件设计大为简单。
3.1.2、RS232接口芯片STC232C
用于构建RS-232转换器,完成串口通信功能,通过该转换器连接电脑就可以下载程序。
3.1.3、串行EEPROM 93C46
3.1.4、串行时钟芯片HT1380
H1380 是一个带秒、分、时、日、日期、月、年的串行时钟保持芯片,每个月多少天以及闰年能自动调节,用若干寄存器存储对应信息,一个 32.768KHz 的晶振校准时钟,为了使用最小引脚,HT1380使用一个I/O口与微信息处理机相连,仅使用三根引线即:/RST复位、SCLK串行时钟、I/O口数据就可以传送 1 字节或 8字节的字符组
编程要点如下:
在开始发送数据之前,先把/RST置高,发送一个带地址和命令信息的8位命令字,紧跟命令之时钟/日历数据传送至相应的寄存器中或从相
应寄存器传送出来(读)。
/RST引脚在数据传送完毕应保持低电平。
所有数据的输入是在SCLK的上升沿有效,输出在SCLK的下降沿有效。
单字节传送需要16个SCLK时钟脉冲,多字节传送需要72个SCLK时钟脉冲,输入、输出数据都是从0位开始。
HT1380还包括两个附加位:时钟停止位(CH)和写保护位(WP),这些位控制振荡器的工作和数据能否写入寄存器中,这两位应首先规定
(为了读、写寄存器组)。
命令字节的格式为:
76543210
100A3A2A1A0R/W
A0~A2:寄存器地址
A3: A3=1 时测试模式,A3=0时常规模式
R/W:为1时读,为 0时写
当命令字节为 1001xxx1时,HT1380 设置在测试模式,这种仅为半导体公司测试时使用,如果使用普通的,不可预测条件的变化。
3.2、单片机最小系统的设计
3.2.1、整体设计框图
系统采用模块化的设计方法,各模块设计方案如下:
3.2.2、单片机正常工作最小系统
单片机正常工作系统包括,振荡电路和上电复位电路,原理图如下:
3.2.3、存储器的扩展
方案一:并行存储器
传统51很多时候都采用并行扩展存储器,技术较为成熟,且较为简单。
方案二:串行存储器
串行存储器扩展用到较少的I/O口,编程简单,在远距离通信时较并行传输有廉价的优势,且随着科技的进步,串口也已走红。
考虑到选用的单片机I/O口有限以及学习串行传输的前瞻性,本设计选择串行存储芯片93C46扩展串行存储器,原理图见完整电路图。
3.2.4、串行口扩展
采用STC232芯片,辅以必要的外围电路,完成扩展要求,其原理图如下:
3.2.5、键盘接口
方案一:A/D键盘
由于STC12C5410AD单片机内部集成8路10位A/D转换器,转换速度可达100KHz(10万次/秒),因此可以用于按键扫描,根据检测到的电压值判断闭合按键的具体位置。
其原理图如下:
该方案合理、合理地利用了单片机内部资源,但不无缺点:按键很多时运算量和误差较大。
方案二:行扫描式键盘,原理图及仿真情况如下:
考虑到键盘模块的复用性,本着尽量节省元件的态度,选择方案二行扫描式键盘,以方便键盘模块用于其它系统,
3.2.6、显示接口
方案一:模拟串口静态显示,原理图如下:
优点:用74HC164静态驱动,仅占用两个I/O口,较动态扫描显示法而言,大大节省了I/O口;缺点:利用芯片较多。
方案二:动态扫描显示
显示原理:在单片机里,首先显示一个数, 然后关掉.然后显示第二个数,又关掉, 那么将看到连续的数字显示,轮流点亮扫描过程中,每位显示器的点亮时间是极为短暂的(约1ms),由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上各位显示器并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感,原理图如下:
综合考虑显示效果和成本,我们选择方案二,利用6位数码管动态扫描显示数据。
3.2.7、AD接口
利用内部集成A/D完成外部模拟信号的采集。
上电复位后P1口为弱上拉型I/O口,可以通过软件将8路中任何一路设置为A/D转换通道,不需作A/D转换时,可以通过模式选择令P1继续作为普通I/O口使用,利用该特性可以将P1
口合理复用。
3.2.8、DA接口
利用内部集成的PWM结合外部电路,利用软件改变PWM脉冲的宽度,结合外部RC滤波电路即可实现D/A转换,原理图如下:
3.2.9、稳压电源
利用变压器和整流桥将市电转变为9V直流电,再通过三端稳压管LM7805得到5V电源,其原理图如下:
3.2.10、总体设计电路
3.3、单片机最小系统应用系统(量程自动转换电压表)设计
仅需要在最小系统的基础上,添加输入调理电路即可实现该应用系统的设计。
3.3.1、自动量程基本控制流程
自动量程转换由初设量程开始,逐级比较,直至选出最合适提量程为止。
自动量程转换的操作流程如上图所示。
继电器或其它控制开关从闭合转变为断开,或从断开转变为闭合有一个短暂的过程,所以在每次改变量程之后要延时一定的时间,然后再进行正式的测量和判断。
为了避免在两种量程的交叉点上可能出现的跳动,还应考虑低量程的超量程比较值和高量程的欠量程比较值之间有一定的重叠范围。
3.3.2、电压量程控制
电压量程部分,先把输入电压进行衰减1/20,然后通过运算放大进行信号的放大,只要改变放大电路的放大倍数,即可实现量程的切换,由于器材的限制,本设计未完成该部分的硬件设计,仅软件仿真成功。
4、系统软件设计
设计平台为Keil 8.08 + Proteus 7.2。
4.1、简单数字电压表软件流程图为:
完整程序见附件。
4.2、量程自动转换的电压表软件设计(仿真成功,但未进行硬件测
试):
4.2.1、量程的设定
MC14051选通 0 放大倍数
0 通道 1.2 倍(MC14051 存在一定的导通电阻)
1通道 2 倍
2 通道 5 倍
3 通道 20 倍
测量电压输入衰减 1/20,设V
in 为要测量的电压,V
t
为衷减后的电压,V
out
为放大后的电压,V
out
最大输出为 5V 则量程范围为: Vin=(5/N)*20 (N 为放大倍数)
MC14051选通 0 最大量程范围
0 通道 83V
1通道 50V
2 通道 20V
3 通道 5V
4.2.2、软件流程
5、系统调试与性能测试
本设计采用模块化设计,焊接、调试均分模块完成。
5.1、焊接测试:
各模块焊接完成后及时用万用表进行测量,测量应连接的点是否正确短接(打到短路档,若连接良好则蜂鸣器会报警)。
显示模块,可用欧姆表(内部含电源)进行测试,将表笔正极接数码管共阳端,负表笔依次接abcdefgh,观察数码管是否正常显示,如不正常,检查焊接情况。
上电后,测量各芯片引脚电压,与理论值相比较,如不同,检查硬件电路。
5.2、软件仿真:
采用单片机仿真软件Proteus进行原理图的仿真,验证设计正确性,大大缩短了开发时间。
Proteus中的仿真图如下(由于其中大多数元件Proteus自带的
仿真库中都没有,只好个人制作):
5.3、硬件测试:
成功完成了单片机最小系统应用设计即简单数字电压表的设计,经测试各模块正常,精度满足要求。
此外还测试了最小系统与上位机(PC机)的通信功能,测试程序见附件。
6、结论
本设计利用较少模块完成了大部分设计要求,实现了0~5V电压的测量,精度为0.01V,由于器材限制,只能给出量程自动转换的思路,这是本设计的一大遗憾。
本设计包含了平时不常做的电源模块的制作,是完整的系统级的设计,通过完成本设计的完整制作,学会如何协调系统各模块之间资源的分配及复用,对系统级设计有更深一次的理解,今后可以独立开发更复杂的系统。
7、参考文献
宏晶科技,STC12C6510AD系列单片机器件手册,2007-11-17
1380串行时钟芯片DataSheet
Microchip Technology,CMOS Serial EEPROM 93C06/46 DataSheet,1995-9 8、附件(绿色文字为注释)
8.1、A/D转换模块和串口模块测试程序(ad_uart_test.c):/*********************************************************
程序:A/D转换模块和串口模块测试程序
文件:ad_uart_test.c
作者:佟川
更新:08.7.23
说明:轮流采集8路模拟数据,并用串口发送到上位机(PC机)。
**********************************************************/
#define uchar unsigned char
#define uint unsigned int
#include <STC12C5410AD.H>
//初始化AD函数,将P18路通道均设为开/漏模式
void InitAd(void)
{
P1M0=0xff;
P1M1=0xff;
}
//初始化串口函数
void InitUart(void)
{
SCON|=0X50;
TH1=TL1=0XFB;
TMOD|=0X20;
ES=1;
TR1=1;
}
//延时函数
void delay(void)
{
uint i;
for(i=0;i<0xfff0;i++);
}
//逐路开始转换并读取AD转换数据函数
void ReadAd(void)
{
uchar temp[16],i;
for(i=0;i<8;i++)
{
ADC_CONTR=i; //选择转换通道
ADC_CONTR|=0x88; //开始转换
while(!(ADC_CONTR&0x10));//等待转换结束
ADC_CONTR=ADC_CONTR&0xef;//将ADC_FLAG软件清零
temp[2*i]=ADC_DATA;//读取高8位
temp[2*i+1]=ADC_LOW2;//读取低2位
}
SBUF=0xa0;
while(!TI);
TI=0;
for(i=0;i<16;i++)
{
SBUF=temp[i];
while(!TI);
TI=0;
}
SBUF=0xf6;
while(!TI);
TI=0;
}
main()
{
InitAd();
InitUart();
while(1)
{
ReadAd();
delay();
}
}
8.2、数字电压表程序(voltmeter.c):
/*********************************************************
程序:简易数字电压表
文件:voltmeter.c
作者:佟川
更新:08.7.23
说明:可以测量0~5V电压,P3.2、P3.3、P3.4做位选,P1.0为模拟输入通道,同时用P1显示数据
**********************************************************/
#include <STC12C5410AD.H>
unsigned char code
dispbitcode[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//对应共阳管0~9
unsigned char dispbuf[3];//显示缓存
unsigned int temp; //用于计算转换量unsigned int getdata; //存储AD转换结果
void Delay1ms(unsigned int i) //1ms延时程序
{
unsigned int j;
for(;i>0;i--)
{
for(j=0;j<125;j++)
{;}
}
}
void Delay25us(unsigned int i) //25us延时程序{
unsigned int j;
for(;i>0;i--)
{
for(j=0;j<31;j++)
{;}
}
}
void Display()
{
P1=dispbitcode[dispbuf[2]]; //段码
P17=0; //点亮小数点 P32=0;
P33=1;
P34=1;
Delay1ms(10);
P1=0xff; //关闭段码
P1=dispbitcode[dispbuf[1]];
P32=1;
P33=0;
P34=1;
Delay1ms(10);
P1=0xff;
P1=dispbitcode[dispbuf[0]];
P32=1;
P33=1;
P34=0;
Delay1ms(10);
P1=0xff;
}
void main()
{
while(1)
{
/*
ADC_CONTR|ADC_POWER|SPEED1|SPEED0|ADC_FLAG|ADC_START|CHS2|CHS1|CHS0| //210个时钟转换一次
1 1 1 0 1 0 0 0
*/ //ADC_CONTR状态
ADC_CONTR=ADC_CONTR|0X80; //10000000 开启转换电源
Delay1ms(1); //延时,等待内部电源稳定
P1M0=P1M0|0X01; //设置p1.0所在通道为开/漏模式
P1M1=P1M1|0X01;
ADC_CONTR=0xe0; //11100000 开启P1.0通道开始转换
Delay25us(10); //延时一端时间,使输入电压达到稳定
ADC_DATA =0x00; //清A/D转换结果寄存器
ADC_LOW2 =0x00;
ADC_CONTR |= 0x08;
//ADC_START=1,开始转换
while(!(ADC_CONTR&0x10)); //0001,0000 等待A/D转换结束
getdata=ADC_DATA*4+(ADC_LOW2&0x03); //读取转换结果
//ADC_CONTR=ADC_CONTR&0xef;
ADC_CONTR=ADC_CONTR&0xe7; //将ADC_FLAG软件清零
Delay25us(1);
P1M0=P1M0&0X00; //设置P1口为普通I/O模式,以便用P1口显示数据。
P1M1=P1M1&0X00;
temp=getdata*1.0/1024*498; //10位AD,1024级量化电平,转换结果的计算公式为转换值= 1024*Vin/Vcc
//temp=255 //测试用
//将A/D转换结果化为10进制
dispbuf[0]=temp%10; //测试时
为5
dispbuf[1]=temp/10%10; //测试时
为2
dispbuf[2]=temp/100; //测试时为2
Display(); //显示数据
}
}
8.3、行扫描键盘程序(key_scan.c)
/*
*************************************************************************** ************
摘要: 4*4小键盘模块程序,供以后其他程序调用.其中P1口高四位接键盘列,P1口低四位接键盘行,
版本: V1.0
完成日期: 2008.4.28
作者: 佟川
*************************************************************************** ************
修改日期: 2008.7.6
版本: V1.2
*************************************************************************** *************
*/
#include <reg51.h>
#define uchar unsigned char
#define keyport P1
//
uchar code seg[16]=
{0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0X88,0X83,0XC6,0XA1,0X86 ,0X8E}; //0~f,共阳极
uchar code keycode[16]=
{0xEE,0XDE,0XBE,0X7E,0XED,0XDD,0XBD,0X7D,0XEB,0XDB,0XBB,0X7B,0XE7,0XD7,0XB7 ,0X77};//待查询的键码值
//
/*
*************************************************************************** ****************
函数名称:delay()
功能描述:延时ms个微妙
入口参数:unsigned int ms
出口参数:无
*************************************************************************** ****************
*/
void delay(unsigned int ms)
{
unsigned char a;
while(!ms--)
for(a=0;a<124;a++);
}
*************************************************************************** ****************
函数名称:keyscan()
功能描述:键盘扫描程序,利用行扫描方式,得到键值
入口参数:无
出口参数:扫描得到的键值~((~sm)+(~fh))
*************************************************************************** ****************
*/
uchar keyscan(void)
{
uchar sm; //存放行扫描代码,该函数的返回值的低四位
uchar fh; //该函数的返回值的高四位
keyport=0xf0; //列置高,行置低
if((keyport&0xf0)!=0xf0) //判断是否有按键按下
{
delay(2); //去抖动延时(1~10ms)
if((keyport&0xf0)!=0xf0)
{
sm=0xfe; //行扫描初值
while((sm&0x10)!=0)
{
keyport=sm;
if((keyport&0xf0)!=0xf0) //若本行有键按下,则执行读取键值信息
{
fh=(keyport&0xf0)|0x0f;
return(~((~sm)+(~fh)));//返回扫描的键值
}
else sm=(sm<<1)|0x01; //若本行没有键按下,则扫描下一行
}
}
}
return 0xff; //若没有按键按下,则返回0xff
}
/*
*************************************************************************** ****************
函数名称:getkey()
功能描述:将扫描得到的键值转化为对应的0~f
入口参数:无
出口参数:显示的数字0~f
*************************************************************************** ****************
uchar getkey()
{
uchar key;
uchar temp;
uchar j;
while(1)
{
key=keyscan();
delay(2);
for(j=0;j<16;j++)
{
if(key==keycode[j])//通过查询方式,得到按下的按键值
{
temp=j; //按键值先保存于temp中
if(key==0xff) //若没有按下下一个键,则一直显示上一个键值
{
return temp;
}
else
{
return j;
temp=j; //更新temp里的值
}
}
}
}
}
/*
*************************************************************************** ****************
测试用函数
*************************************************************************** ****************
*/
///*
void main(void)
{
uchar ch;
// P3&=0xfe;
while(1)
{
ch=getkey();
P2=seg[ch]; //P0口接数码管
} }//*/。