通信工程学院
课程设计说明书
题 目 信号发生器的设计
课 程 名 称 单片机原理及应用A
专 业 电子信息工程
班 级 K电信ZB102
学 生 姓 名 刘婷婷
学 号 240106807
设 计 地 点 信息楼C210
指 导 教 师 宗 慧
起 止 日 期 2013-6-17/24至2013-6-21/28
一、课程设计目的
二、课程设计任务
三、课程设计要求
四、课程设计思路
五、课程设计软件仿真结果截图
六、课程设计体会
七、主要参考文献
八、附录:源程序代码
1、课程设计目的:
在学习《单片机原理及应用A》课程的基础上,进一步深入理解MCS-51单片机的结构、工作原理和应用技术,提高单片机控制系统设计、研发的能力;按照教学计划的要求,利用一周时间,综合应用所学知识,设计具有一定功能的小型单片机控制系统,培养学生一定的自学能力和分析问题、解决问题的能力,要求学生能通过思考、查阅工具书、参考文献,提出自己的设计方案,找出设计中遇到问题的解决途径。
2、课程设计要求:
1、整个课程设计的各个环节都要自己动手。
2、通过TLC5615串行D/A转换芯片完成信号发生器设计,经由示波器观察信号波形;
3、采用C语言编程实现;
4、其他要求参见“nKDE-51单片机实验教学系统实验指导书;
5、基本任务为必做项目,附加任务为选做项目;
6、对课程设计进行总结,撰写课程设计说明书。
三、课程设计任务:
1、基本任务:利用nKDE-51单片机实验教学系统上的硬件资源,实现信号发生器的功能。
2、附加任务:通过键盘(1)选择输出信号的波形;
(2)调整幅度、频率等参数。
3、工作量要求:(1)设计的硬件电路图与程序流程图;
(2)源程序代码;
(3)系统运行结果符合课程设计要求。
四、课程设计思路:
1、TLC5615芯片结构:
引脚功能:DIN:串行数据输入端 OUT SCLK
SCLK:串行时钟输入端 REFin CS
CS:片选端,低电平有效 DIN
OUT:DAC模拟电压输出端 DOUT
REFin:基准输入端
2、TLC5615芯片工作原理:
TLC5615由16位转换寄存器、控制逻辑、10位DAC寄存器、上电复位、DAC、外部基准放大器、基准电压倍增器等部分组成。
TLC5615通过固定增益为2 的运放缓冲电阻串接网络,把10位数字数据转换成模拟电压。上电时,内部电路吧10DAC寄存器复位至全0,其输出具有与基准输入相同的极性。
(1)数据输入。由于DAC是12位寄存器,所以在写入10位数据后,最低2位写入2个“0”。
(2)输出缓冲器。输出缓冲器具有满电源电压幅度输出,它带有短路保护并能驱动有100pF负载电容的2kΩ负载。
(3)外部基准。外部基准电压输入经过缓冲,使得DAC输入电阻与代码无关。因此,REFin的输入电阻为10MΩ,输入电容典型值为5pF,它们与输入代码无关。基准电压决定DAC的满度输出。
(4)逻辑接口。逻辑输入端可使用TTL或CMOS逻辑电平。使用满电源电压幅度时,CMOS逻辑可得到最小的功耗。使用TTL逻辑电平是,功耗需求增加约2倍。
(5)串行时钟和更新速率。TLC5615的最大串行时钟频率近似为14MHz。通常,数字更新速率受片选周期的。对于满度输入阶跃跳变,10位DAC的建立时间约为12.5μs,这把更新频率在80KHz。
当片选信号为低电平时,输入数据读入16bit移位寄存器。SCLK输入的上升沿把数据移入输入寄存器,接着,CS的上升沿把数据传送至DAC寄存器,当CS为高电平时,输入的数据不能由时钟同步送入输入寄存器。所有CS的跳变应发生在SCLK输入为低电平时。
DIN只需要输入12位数据,DIN输入的12位数据中,前10位为TLC5615输入的D/A转换数据,并且输入时,高位在前,低位在后,后2位必须写入为0的2位数值,因为TLC5615的DAC输入锁存器为12位宽。
3、总流程图:
4、程序编译及软件仿真电路原理图:
元器件列表:
元器件名称 | 所属类型 |
ATC51 | Microprocessor ICS |
CRYSTAL 晶振 | Misecllaneous |
CAP 电容 | Capacitor |
RESPACK-8 | Resistor |
CAP电容 | Capacitor |
SWITCH按键 | Switches&relays |
TLC5615C(L)D | Data Converters |
LM016L液晶显示 | Display |
1、按下三角波键示波器输出三角波,同时液晶屏上显示“san jiao bo”
2、按下“锯齿波”键示波器输出三角波,同时液晶屏上显示“ju chi bo”
3、按下“方波”键示波器输出三角波,同时液晶屏上显示“fang bo”
4、按下“正弦波”键示波器输出三角波,同时液晶屏上显示“sine”
5、当无任何键按下时示波器输出直线,同时液晶屏上显示“wave”
6、显示字符“三”:
6、课程设计体会:
本次课程设计我做的是信号发生器,参考相关书籍和老师给的程序,很快就把三角波、锯齿波、方波、正弦波四种波形显示出来了。后面就是波形显示切换和在液晶屏上显示对应波形说明的问题。在老师同学和自己的努力下,在原程序上利用IF语句和SWITCH语句实现了波形按键切换功能,即想要显示方波按下“方波”键即可。另外我们这组还在LCM 1602液晶屏上显示出了汉字,通过参考资料加上自己对汉字显示原理的理解,最终在液晶屏上显示出汉字“三”,虽然只是简单的“三”,但是过程是相当不容易。这次课程设计很有趣,让我实实在在收获了不少东西,知道了DA转换和LCM1602显示的原理,尤其是在LCM 1602汉字的显示原理。这次课程设计也提高了我的编程能力和同学的合作能力。
7、主要参考文献:
1、《nKDE51单片机实验教学系统实验指导书》南京邮电大学,2011年
2、《单片机原理与应用及C51程序设计》(第2版),谢维成等编著,清华大学出版社,2009年
3、《单片机原理及应用》(第2版),李建忠,西安电子科技大学出版社,2008年
4、《基于protues的51系列单片机设计与仿真》侯玉宝 陈忠平 李成群等编著,电子工业出版社
八、源程序代码:
LCM1602.H
#ifndef LCM1602_h
#define LCM1602_h
#define BUSYFLAG 0x80
#define BLINK 0x01
#define NOBLINK 0x00
unsigned char LCMReadState(void);
void LCMDelay(int);
void LCMWriteCmd(unsigned char);
void LCMWriteData(unsigned char);
void LCMClear(void);
void LCMInit(void);
void LCMGotoXY(unsigned char,unsigned char);
void LCMDisplayChar(unsigned char,unsigned char,unsigned char);
void LCMDisplayString(unsigned char,unsigned char,unsigned char*);
void LCMBlink(unsigned char,unsigned char,unsigned char);
#endif
BOXING.H
#include #include #include #include #define OSC 22118400 #define BAUDRATE 9600 sbit DIN = P1^4; //串行数据输入端 sbit SCK = P1^5; //串行时钟输入端 sbit CS = P1^6; //DA片选端 sbit S0 = P2^0; // 三角波 sbit S1 = P2^1; // 锯齿波 sbit S2 = P2^2; // 方波波 sbit S3 = P2^3; // 正弦波 //正弦波 unsigned char code type[256]={ 0x80,0x83,0x86,0x,0x8c,0x90,0x93,0x96,0x99,0x9c,0x9f,0xa2,0xa5,0xa8,0xab, 0xae,0xb1,0xb3,0xb6,0xb9, 0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8,0xda,0xdc,0xde, 0xe0,0xe2,0xe4,0xe6,0xe8, 0xea,0xeb,0xed,0xef,0xf0,0xf1,0xf3,0xf4,0xf5,0xf6,0xf8,0xf9,0xfa,0xfa,0xfb, 0xfc,0xfd,0xfd,0xfe,0xfe, 0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xfd,0xfd,0xfc,0xfb, 0xfa,0xfa,0xf9,0xf8,0xf6, 0xf5,0xf4,0xf3,0xf1,0xf0,0xef,0xed,0xeb,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde, 0xdc,0xda,0xd8,0xd5,0xd3, 0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3,0xb1,0xae,0xab, 0xa8,0xa5,0xa2,0x9f,0x9c, 0x99,0x96,0x93,0x90,0x8c,0x,0x86,0x83,0x80,0x7d,0x7a,0x77,0x74,0x70,0x6d, 0x6a,0x67,0x,0x61,0x5e, 0x5b,0x58,0x55,0x52,0x4f,0x4d,0x4a,0x47,0x44,0x41,0x3f,0x3c,0x39,0x37,0x34, 0x32,0x2f,0x2d,0x2b,0x28, 0x26,0x24,0x22,0x20,0x1e,0x1c,0x1a,0x18,0x16,0x15,0x13,0x11,0x10,0x0f,0x0d, 0x0c,0x0b,0x0a,0x08,0x07, 0x06,0x06,0x05,0x04,0x03,0x03,0x02,0x02,0x02,0x01,0x01,0x00,0x00,0x00,0x01, 0x01,0x02,0x02,0x02,0x03, 0x03,0x04,0x05,0x06,0x06,0x07,0x08,0x0a,0x0b,0x0c,0x0d,0x0f,0x10,0x11,0x13, 0x15,0x16,0x18,0x1a,0x1c, 0x1e,0x20,0x22,0x24,0x26,0x28,0x2b,0x2d,0x2f,0x32,0x34,0x37,0x39,0x3c,0x3f, 0x41,0x44,0x47,0x4a,0x4d, 0x4f,0x52,0x55,0x58,0x5b,0x5e,0x61,0x,0x67,0x6a,0x6d,0x70,0x74,0x77,0x7a, 0x7d}; void DAConvert(unsigned int da) //并行转串行 { int i; da <<= 2; da &= 0xFFC; SCK = 0; CS = 0; for(i=0;i<12;i++) { if(da & 0x800) DIN = 1; else DIN = 0; SCK = 1; SCK = 0; da <<= 1; } CS = 1; SCK = 1; DIN = 1; } void Delay(unsigned int t) { unsigned int i; while(t--) {for(i=0;i<100;i++);} } void ling () { LCMClear() ; LCMDisplayString(1,5,"wave "); while(1) { DAConvert(0); if(S0==0||S1==0||S2==0||S3==0)break; } } void sanjiaobo() { LCMClear() ; LCMDisplayString(1,2,"san jiao bo"); while(1) { unsigned int i; for(i=0;i<256;i++) {DAConvert(i);} for (i=256;i>0;i--) { DAConvert(i);} if(S0==1)break;} } void juchibo() { LCMClear() ; LCMDisplayString(1,2,"ju chi bo"); while(1) { unsigned int i; for (i=0;i<256;i++) { DAConvert(i);} if(S1==1)break;} } void fangbo() { LCMClear() ; LCMDisplayString(1,2,"fang bo"); while (1) { DAConvert(40); Delay(50); DAConvert(0); Delay(50); if(S2==1)break; } } void sine() { LCMClear() ; LCMDisplayString(1,5,"sine"); while(1) { unsigned char i; DAConvert(type[i]); i++; if(S3==1)break;} } void boxing(void) { int key=0; while(1) { if ( S0==1&&S1==1 && S2==1 &&S3==1 ) key=0; if ( S0==0) key=1; if ( S1==0) key=2; if ( S2==0) key=3; if ( S3==0) key=4; switch (key) {case 0: ling(); break; case 1: sanjiaobo(); break; case 2: juchibo(); break; case 3: fangbo(); break; case 4: sine(); break; } } } LCM1602.C #include #include #include #include #define BUSYFLAG 0x80 #define BLINK 0x01 #define NOBLINK 0x00 #define LCM_DB P0 sbit LCM_RS = P1^0; sbit LCM_RW = P1^1; sbit LCM_E = P1^2; sbit LCM_BLC = P1^3; unsigned int data DelayConst = 140; /****************************************************************************** 函数名:LCMDelay 功 能:通过循环的方式延时 参 数:int,表示要延时的毫秒数 ******************************************************************************/ void LCMDelay(int ms) { unsigned int i,cnt; cnt = DelayConst * ms; for(i=0;i /****************************************************************************** 函数名:LCMReadState 功 能:查询LCM的忙标志/当前AC地址 返 回:BYTE,最高bit为1表示忙,为0表示闲 ******************************************************************************/ unsigned char LCMReadState(void) { unsigned char state; LCM_E = 0; LCM_RS = 0; LCM_RW = 1; LCM_E = 1; _nop_(); _nop_(); state = LCM_DB; LCM_E = 0; return state; } /******************************************************************************* 函数名:LCMClear 功 能:清屏 *******************************************************************************/ void LCMClear(void) { LCMDelay(1); LCM_E = 0; LCM_RS = 0; LCM_RW = 0; LCM_DB = 0x01; LCM_E = 1; _nop_(); _nop_(); LCM_E = 0; LCMDelay(1); } /******************************************************************************* 函数名:LCMWriteCmd 功 能:向LCM写入控制字 参 数:BYTE,命令字节。写入前不判断忙表示(因为初始化过程中不能判断) *******************************************************************************/ void LCMWriteCmd(unsigned char cmd) { LCMDelay(1); LCM_E = 0; LCM_RS = 0; LCM_RW = 0; LCM_DB = cmd; LCM_E = 1; _nop_(); _nop_(); LCM_E = 0; } /****************************************************************************** 函数名:LCMWriteData 功 能:向LCM写入数据 参 数:BYTE,将要写入的数据 ******************************************************************************/ void LCMWriteData(unsigned char dc) { while(LCMReadState() & BUSYFLAG); LCM_RS = 1; LCM_RW = 0; LCM_DB = dc; LCM_E = 1; _nop_(); _nop_(); LCM_E = 0; } /****************************************************************************** 函数名:LCMInit 功 能:初始化LCM 参 数:DWORD,晶振频率(Hz),供计算延时常数 ******************************************************************************/ void LCMInit(void) { LCMDelay(60); // 延时60ms,等待LCM复位 LCMWriteCmd(0x38); // 功能设置:8位接口,2行,5x7字符点阵 LCMDelay(5); // 延时 LCMWriteCmd(0x38); // 第二次 LCMDelay(1); // 延时 LCMWriteCmd(0x38); // 此后可以通过监测忙标志判断指令执行情况 while(LCMReadState() & BUSYFLAG); LCMWriteCmd(0x08); // 关闭显示 while(LCMReadState() & BUSYFLAG); LCMWriteCmd(0x01); // 清屏 while(LCMReadState() & BUSYFLAG); LCMWriteCmd(0x06); // 显示地址自动增量,整体不移位 while(LCMReadState() & BUSYFLAG); LCMWriteCmd(0x0e); // 开显示,开光标,不闪烁 while(LCMReadState() & BUSYFLAG); } /****************************************************************************** 函数名:LCMGotoXY 功 能:移动光标到X行,Y列 参 数:BYTE,x表示行(0,1),y表示列(横向,取值0~0x0f) ******************************************************************************/ void LCMGotoXY(unsigned char x,unsigned char y) // x:行(0~1) y:列(0~F) { unsigned char cmd; if(x==0) { cmd = 0x80 | y; } else { cmd = 0x80 | 0x40 | y; //(第1行第0列为40H开始) } LCMWriteCmd(cmd); while(LCMReadState() & BUSYFLAG); } /****************************************************************************** 函数名:LCMDisplayString 功 能:从指定的位置开始显示字符串 参 数:x表示行(0,1),y表示列(横向,取值0~0x0f),*str为指向将要显示的字符串的指针 ******************************************************************************/ void LCMDisplayString(unsigned char x,unsigned char y,unsigned char* str) { unsigned char ptr; ptr = 0; while(*(str+ptr) != 0) { LCMDisplayChar(x,(y+ptr),*(str+ptr)); ptr++; } } #include #include #define BUSYFLAG 0x80 #define BLINK 0x01 #define NOBLINK 0x00 #define OSC 22118400 unsigned char ucTH,ucTL,Ticks; //***************************************************************************** // 函数名:T0ISR // 功 能:50ms中断服务程序 //***************************************************************************** void T0ISR(void) interrupt 1 { TH0 = ucTH; TL0 = ucTL; TR0 = 1; Ticks ++; if(Ticks == 20) { Ticks = 0; LCM_BLC = 0; } } void main(void) { // 初始化 EA = 0; // 停止所有中断 Ticks = 0; ucTH = (65536-OSC/12/20)/256; // 计算50ms定时的时间常数 ucTL = (65536-OSC/12/20)%256; TMOD = 0x01; // T0:模式1,16位定时器 TH0 = ucTH; TL0 = ucTL; ET0 = 1; // T0允许中断 TR0 = 1; // 启动定时器 EA = 1; // 打开总中断允许 LCMInit(); LCMClear(); while(1) {boxing();} } 汉字显示程序 #include #define uint unsigned int #define uchar unsigned char sbit rs=P1^0; sbit rw=P1^1; sbit en=P1^2; sbit LCM_BLC = P1^3; //字符“三” uchar code table[]={0x00,0x00,0x3F,0x00,0x00,0x00,0x00,0x0F,//“三”左上半部分 0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x7C, //“三”右上半部分 0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00, //“三”左下半部分 0x00,0x00,0x00,0x00,0x00,0x7F,0x00,0x00//“三”右下半部分 }; void delay(uint n) //延时 { uint x,y; for(x=n;x>0;x--) for(y=110;y>0;y--); } void lcd_wcom(uchar com) //向lcm1602写入命令字 { rs=0; rw=0; P0=com; delay(5); en=1; en=0; } void lcd_wdat(uchar dat) //向lcm1602写入数据 { rs=1; rw=0; P0=dat; delay(5); en=1; en=0; } void lcd_init() //lcm1602初始化 { lcd_wcom(0x38); lcd_wcom(0x0c); lcd_wcom(0x06); lcd_wcom(0x01); } void main() { char m=0; LCM_BLC = 0; lcd_init(); lcd_wcom(0x40); //设定CGRAM地址 for(m=0;m<;m++) //将代码写入CGRAM中 { lcd_wdat(table[m]); } lcd_wcom(0x85); //设定上排的显示位置 for(m=0;m<2;m++) { lcd_wdat(m); } lcd_wcom(0xc5); //设定下排的显示位置 for(m=2;m<4;m++) { lcd_wdat(m); } while(1); }