摘要 2
第1章 概述 3
1.1 ADC0832调节频率输入实现的意义 3
第2章 频率计实现的理论分析 3
2.1 ADC0832调节频率输出的基本结构和原理 3
第3章 单片机基础与芯片使用 4
3.1单片机介绍 4
3.2 ADC0832介绍和时序使用 7
第4章 系统方案设计及实现 11
4.1 单片机选取 11
4.2 系统硬件结构图 13
4.3 各模块的实现 13
4.4 软件的实现 15
4.5 功能调试 24
结束语 26
参考文献 27
致谢 28
摘要
“ADC0832控制频率输出”实质上是运用可调电阻反馈电压模拟量输入到ADC0832中输出数字量。应用数字量填充单片机定时器初值,可产生中断从而实现电平转换,接到示波器上可观察方波的输出,由数码管直观的看出电平变化频率。设计的关键在于数模转换,这个由ADC0832来实现,所以可以比较容易得到一个可控制的频率计。
本文以单片机的实际应用为背景,介绍了以单片机为核心ADC0832控制频率输出设计的基本结构和基本原理。
关键词:单片机;ADC0832;数模转换
Abstract
"ADC0832 control frequency output" is actually using the adjustable resistorfeedback analog voltage input to the ADC0832 digital output. Application ofdigital single-chip timer initial filling, can generate an interrupt to realize the conversion level, received the oscilloscope can observe Fang Bo's output, by the digital tube directly see level change frequency. The key lies in the design of digital to analog conversion, this is implemented by ADC0832, so it can be easily obtained a controlled frequency meter.
Based on the background of the practical application of SCM, SCM introduced to the basic structure of frequency output control design of the core and basic principle of ADC0832.
Keyword: MCU; ADC0832; digital to analog conversion
第1章 概述
1.1 ADC0832调节频率输入实现的意义
应用ADC0832和可调电阻,由可调电阻反馈电压模拟量输入到中输出数字量。应用数字量填充单片机定时器初值,可产生中断从而实现电平转换,接到示波器上可观察方波的输出。调节可调电阻,来改变频率快慢,如果外接电机的话就可以用这个来改变电机速度。
第2章 频率计实现的理论分析
2.1 ADC0832调节频率输出的基本结构和原理
原理是改变单片机定时器1的初值产生不同时间的中断来实现高低电平的转换,而产生频率可变的方波。改变初值的方法是由可调电阻反馈电压模拟量输入到ADC0832中输出数字量。应用数字量填充单片机定时器初值,可产生中断从而实现电平转换,接到示波器上可观察方波的输出。调节可调电阻,来改变频率快慢。
图2.1 ADC0832调节频率输出的基本结构
第3章 单片机基础与芯片使用
3.1单片机介绍
STCC51单片机的介绍
STC系列单片机是美国STC公司最新推出的一种新型51内核的单片机。片内含有Flash程序存储器、SRAM、UART、SPI、A\\D、PWM等模块。该器件的基本功能与普通的51单片机完全兼容。
3.1.1主要功能、性能参数
1.内置标准51内核,机器周期:增强型为6时钟,普通型为12时钟;
2.工作频率范围:0~40MHZ,相当于普通8051的0~80MHZ;
3.STCC5xRC对应Flash空间:4KB\\8KB\\15KB;
4.内部存储器(RAM):512B;
5.定时器\计数器:3个16位;
6.通用异步通信口(UART)1个;
7.中断源:8个;
8.有ISP(在系统可编程)\IAP(在应用可编程),无需专用编程器\仿真器;
9.通用I\\O口:32\\36个;
10.工作电压:3.8~5.5V;
11.外形封装:40脚PDIP、44脚PLCC和PQFP等
3.1.2 C51单片机的引脚功能说明
图3.1 ATC51封装
(1)VCC:电源电压
(2) GND:地
(3)P0口:P0口是一组8位漏极开路型双向I/O口,也即地址/数据总线复用口。作为输出口用时,每位能吸收电流的方式驱动8个TTL逻辑门电路,对端口P0写“1”时可作为高阻抗输入端用。在访问外部数据存储器或程序存储器时,这组口线分时转换地址(低8位)和数据总线复位,在访问期间激活内部上拉电阻。
(4) P1口:P1是一个带内部上拉电阻的8位双向I/O口,P1的输出缓冲级可驱动(吸收或输出电流)4个TTE逻辑门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作输入口。作输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流(ILL)。与ATC51不同之处是,P1.0和P1.1还可分别作为定时/计数器2的外部计数输入(P 1.0/T2)和输入(P 1.1/T2EX ),参见表3.1。Flash编程和程序校验期间,P1接收低8位地址。
表3.1 P1.0和P1.1的第二功能
| 引 脚 号 | 功能特性 |
| P1.0 | T2(定时/计数器2外部计数脉冲输入),时钟输出 |
| P1.1 | T2EX(定时/计数2捕获/重装载触发和方向控制) |
(6)P3口:P3口是一组带有内部上拉电阻的8位双向I/O口。P3口输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对P3口写入“1”时,它们被内部上拉电阻拉高并可作为输入端口。此时,被外部拉低的P3口将用上拉电阻输出电流(ILL)。P3口除了作为一般的I/O口线外,更重要的用途是它的第二功能,如表3.2所示。
(7) RST:复位输入。当振荡器工作时,RST引脚出现两个机器周期以上高电平将使单片机复位。
表3.2 P3口的第二功能
| 端口引脚 | 第二功能 |
| P3.0 | RXD(串行输入口) |
| P3.1 | TXD(串行输出口) |
| P3.2 | (外中断0) |
| P3.3 | (外中断1) |
| P3.4 | T0(定时/计数0) |
| P3.5 | T1(定时/计数1) |
| P3.6 | (外部数据存储器写选通) |
| P3.7 | (外部数据存储器读选通) |
(9)XTAL1:振荡器反相放大器的及内部时钟发生器的输入端。
(10)XTAL2:振荡器反相放大器的输出端。
(11)数据存储器:C51有256个字节的内部RAM,80H-FFH高128个字节与特殊功能寄存器(SFR)地址是重叠的,也就是高128。字节的RAM和特殊功能寄存器的地址是相同的,但在物理上它们是分开的。当一条指令访问7FH以上的内部地址单元时,指令中使用的寻址方式是不同的,也即寻址方式决定是访问高128字节。RAM还是访问特殊功能寄存器。如果指令是直接寻址方式则为访问特殊功能寄存器。
(12)中断:C51共有6个中断向量:两个外中断(INT0和INT1),3个定时器中断(定时器0, 1, 2)和串行口中断。
(13)时钟振荡器:C51中有一个用于构成内部振荡器的高增益反相放大器,引脚XTAL1和XTAL2分别是该放大器的输入端和输出端。这个放大器与作为反馈元件的片外石英晶体或陶瓷谐振器一起构成自激振荡器,振荡电路参见图3.2所示。外接石英晶体(或陶瓷谐振器)及电容C1、C2接在放大器的反馈回路中构成并联振荡电路,对外接电容C1、C2虽然没有十分严格的要求,但电容容量的大小会轻微影响振荡频率的高低、振荡器工作的稳定性、起振的难易程度及温度稳定性,如果使用石英晶体,我们推荐电容使用30pF士10pF,而如果使用陶瓷谐振器,建议选择40pF士l0pF。用户也可以采用外部时钟。采用外部时钟的电路如图3.3图所示。这种情况下,外部时钟脉冲接到XTAL1端,即内部时钟发生器的输入端,XTAL2则悬空。
图3.2 内部振荡电路 图3.3 外部振荡电路
由于外部时钟信号是通过一个2分频触发器后作为内部时钟信号的,所以对外部时钟信号的占空比没有特殊要求,但最小高电平持续时间和最大的低电平持续时间应符合产品技术条件的要求。
3.2 ADC0832介绍和时序使用
ADC0832 是美国国家半导体公司生产的一种 8 位分辨率、双通道 A/D 转换芯片。由于它体积小,兼容性强,性价比高而深受单片机爱好者及企业欢迎,其目前已经有很高的普及率。
ADC0832 具有以下特点:
8 位分辨率;
双通道 A/D 转换;
输入输出电平与 TTL/CMOS 相兼容;
5V 电源供电时输入电压在 0~5V 之间;
工作频率为 250KHZ,转换时间为 32μS;
一般功耗仅为 15mW;
8P、14P—DIP(双列直插)、PICC 多种封装;
商用级芯片温宽为0°C to +70°C,工业级芯片温宽为−40°C to +85°C;
芯片接口说明:
CS 选使能,低电平芯片使能。
CH0 输入通道 0,或作为 IN+/-使用。
CH1 输入通道 1,或作为 IN+/-使用。
GND 参考 0 电位(地)。
DI 号输入,选择通道控制。
DO 号输出,转换数据输出。
CLK 片时钟输入。
VCC/REF 源输入及参考电压输入(复用)。
图3.4 ADC0832封装
图3.5 ADC0832 与单片机的接口电路
ADC0832 为 8 位分辨率 A/D 转换芯片,其最高分辨可达 256 级,可以适应一般的模拟量转换要求。其内部电源输入与参考电压的复用,使得芯片的模拟电压输入在 0~5V 之间。芯片转换时间仅为 32μS,据有双数据输出可作为数据校验,以减少数据误差,转换速度快且稳定性能强。的芯片使能输入,使多器件挂接和处理器控制变的更加方便。通过 DI 数据输入端,可以轻易的实现通道功能的选择。
单片机对 ADC0832 的控制原理:
正常情况下 ADC0832 与单片机的接口应为 4 条数据线,分别是 CS、CLK、DO、DI。但由于 DO 端与 DI 端在通信时并未同时有效并与单片机的接口是双向的,所以电路设计时可以将 DO 和 DI 并联在一根数据线上使用。(见图 3.6)当 ADC0832 未工作时其 CS 输入端应为高电平,此时芯片禁用,CLK 和DO/DI 的电平可任意。当要进行 A/D 转换时,须先将 CS 使能端置于低电平并且保持低电平直到转换完全结束。此时芯片开始转换工作,同时由处理器向芯片时钟输入端 CLK 输入时钟脉冲,DO/DI 端则使用 DI 端输入通道功能选择的数据信号。在第 1 个时钟脉冲的下沉之前 DI 端必须是高电平,表示启始信号。在第 2、3 个脉冲下沉之前 DI 端应输入 2 位数据用于选择通道功能,其功能项见图3.6
图3.6 数据通道选择
如表3.3所示,当此 2 位数据为“1”、“0”时,只对 CH0 进行单通道转换。当 2 位数据为“1”、“1”时,只对 CH1 进行单通道转换。当 2 位数据为“0”、“0”时,将 CH0 作为正输入端 IN+,CH1 作为负输入端 IN-进行输入。当 2 位数据为“0”、“1”时,将 CH0 作为负输入端 IN-,CH1 作为正输入端 IN+进行输入。到第 3 个脉冲的下沉之后 DI 端的输入电平就失去输入作用,此后 DO/DI端则开始利用数据输出 DO 进行转换数据的读取。从第 4 个脉冲下沉开始由 DO端输出转换数据最高位 DATA7,随后每一个脉冲下沉 DO 端输出下一位数据。直到第 11 个脉冲时发出最低位数据 DATA0,一个字节的数据输出完成。也正是从此位开始输出下一个相反字节的数据,即从第 11 个字节的下沉输出 DATD0。随后输出 8 位数据,到第 19 个脉冲时数据输出完成,也标志着一次 A/D 转换的结束。最后将 CS 置高电平禁用芯片,直接将转换后的数据进行处理就可以了。更详细的时序说明请见图3.6。
图3.7 ADC0832时序
作为单通道模拟信号输入时 ADC0832 的输入电压是 0~5V 且 8 位分辨率时的电压精度为 19.53mV。如果作为由 IN+与 IN-输入的输入时,可是将电压值设定在某一个较大范围之内,从而提高转换的宽度。但值得注意的是,在进行 IN+与 IN-的输入时,如果 IN-的电压大于 IN+的电压则转换后的数据结果始终为00H。
图3.8 ADC0832 数据读取程序流程
ADC0832 芯片接口程序的编写:
由于 ADC0832 的数据转换时间仅为 32μS,所以 A/D 转换的数据采样频率可以很快,从而也保证的某些场合对 A/D转换数据实时性的要求。数据读取程序以子程序调用的形式出现。
第4章 系统方案设计及实现
4.1 单片机选取
ATC5指令简单,易学易懂,外围电路简单,硬件设计方便,io口操作简单,无方向寄存器,资源丰富,一般设计足够用了,价格便宜、容易购买,资料丰富容易查到,程序烧写简单,好多的优点的使用功能最主要是性价比高,网上也有很多成熟的例程可以让你参考,外围的电路简单,芯片能满足一般。ATC51是一种带4K字节闪烁可编程可擦除只读存储器(FPEROM—Falsh Programmable and Erasable Read Only Memory)的低电压,高性能CMOS8位微处理器,俗称单片机。该器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。由于将多功能8位CPU和闪烁存储器组合在单个芯片中,ATMEL的ATC51是一种高效微控制器,为很多嵌入式控制系统提供了一种灵活性高且价廉的方案。
P0口:P0口为一个8位漏级开路双向I/O口,每脚可吸收8TTL门电流。当P1口的管脚第一次写1时,被定义为高阻输入。P0能够用于外部程序数据存储器,它可以被定义为数据/地址的第八位。在FIASH编程时,P0 口作为原码输入口,当FIASH进行校验时,P0输出原码,此时P0外部必须被拉高。
P1口:P1口是一个内部提供上拉电阻的8位双向I/O口,P1口缓冲器能接收输出4TTL门电流。P1口管脚写入1后,被内部上拉为高,可用作输入,P1口被外部下拉为低电平时,将输出电流,这是由于内部上拉的缘故。在FLASH编程和校验时,P1口作为第八位地址接收。
P2口:P2口为一个内部上拉电阻的8位双向I/O口,P2口缓冲器可接收,输出4个TTL门电流,当P2口被写“1”时,其管脚被内部上拉电阻拉高,且作为输入。并因此作为输入时,P2口的管脚被外部拉低,将输出电流。这是由于内部上拉的缘故。P2口当用于外部程序存储器或16位地址外部数据存储器进行存取时,P2口输出地址的高八位。在给出地址“1”时,它利用内部上拉优势,当对外部八位地址数据存储器进行读写时,P2口输出其特殊功能寄存器的内容。P2口在FLASH编程和校验时接收高八位地址信号和控制信号。
P3口:P3口管脚是8个带内部上拉电阻的双向I/O口,可接收输出4个TTL门电流。当P3口写入“1”后,它们被内部上拉为高电平,并用作输入。作为输入,由于外部下拉为低电平,P3口将输出电流(ILL)这是由于上拉的缘故。
RST:复位输入。当振荡器复位器件时,要保持RST脚两个机器周期的高电平时间。
ALE/PROG:当访问外部存储器时,地址锁存允许的输出电平用于锁存地址的地位字节。在FLASH编程期间,此引脚用于输入编程脉冲。在平时,ALE端以不变的频率周期输出正脉冲信号,此频率为振荡器频率的1/6。因此它可用作对外部输出的脉冲或用于定时目的。然而要注意的是:每当用作外部数据存储器时,将跳过一个ALE脉冲。如想禁止ALE的输出可在SFR8EH地址上置0。此时, ALE只有在执行MOVX,MOVC指令是ALE才起作用。另外,该引脚被略微拉高。如果微处理器在外部执行状态ALE禁止,置位无效。
/PSEN:外部程序存储器的选通信号。在由外部程序存储器取指期间,每个机器周期两次/PSEN有效。但在访问外部数据存储器时,这两次有效的/PSEN信号将不出现。
EA/VPP:当/EA保持低电平时,则在此期间外部程序存储器(0000H-FFFFH),不管是否有内部程序存储器。注意加密方式1时,/EA将内部锁定为RESET;当/EA端保持高电平时,此间内部程序存储器。在FLASH编程期间,此引脚也用于施加12V编程电源(VPP)。
XTAL1:反向振荡放大器的输入及内部时钟工作电路的输入。
XTAL2:来自反向振荡器的输出。
振荡器特性:
XTAL1和XTAL2分别为反向放大器的输入和输出。该反向放大器可以配置为片内振荡器。石晶振荡和陶瓷振荡均可采用。如采用外部时钟源驱动器件,XTAL2应不接。有余输入至内部时钟信号要通过一个二分频触发器,因此对外部时钟信号的脉宽无任何要求,但必须保证脉冲的高低电平要求的宽度。
芯片擦除:
整个PEROM阵列和三个锁定位的电擦除可通过正确的控制信号组合,并保持ALE管脚处于低电平10ms 来完成。在芯片擦操作中,代码阵列全被写“1”且在任何非空存储字节被重复编程以前,该操作必须被执行。
此外,ATC51设有稳态逻辑,可以在低到零频率的条件下静态逻辑,支持两种软件可选的掉电模式。在闲置模式下,CPU停止工作。但RAM,定时器,计数器,串口和中断系统仍在工作。在掉电模式下,保存RAM的内容并且冻结振荡器,禁止所用其他芯片功能,直到下一个硬件复位为止。
4.2 系统硬件结构图
图4.1系统硬件结构
4.3 各模块的实现
图4.2 最小系统模块
图4.3 模数转换模块
图4.4 显示模块
图4.5 原理图
4.4 软件的实现
ADC0832驱动子程序:
#include #include unsigned char tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x83,0xf8,0x80,0x98}; sbit AD0832_CS = P1^0 ; sbit AD0832_CLK = P1^3; sbit AD0832_DI = P1^4; void main( void) { unsigned char i=0 , x =0 , y = 0 ; unsigned int temp=0; while(1) { AD0832_CLK = 0 ; AD0832_DI = 1 ; AD0832_CS = 0 ; _nop_(); AD0832_CLK = 1 ; _nop_(); AD0832_CLK = 0 ; AD0832_DI = 1 ; _nop_(); AD0832_CLK = 1 ; _nop_(); y = y | 0x80; AD0832_DI = 0 ; _nop_(); AD0832_CLK = 1 ; _nop_(); AD0832_CLK = 0 ; AD0832_DI = 1 ; for(i = 0 ; i<8 ; i++) { AD0832_CLK = 1 ; _nop_(); AD0832_CLK = 0 ; x = x<<1; if(AD0832_DI ==1) x = x | 0x01; } for(i = 0 ; i<8 ; i++) { y = y>>1; if(AD0832_DI ==1) AD0832_CLK = 1 ; _nop_(); AD0832_CLK = 0 ; } AD0832_CLK = 1 ; AD0832_DI = 1 ; AD0832_CS = 1 ; if(x==y) { temp = x *2 ; P0 = tab[temp/100%10]; P2 = tab[temp/10%10]; } } } uint x=Read_AD()*30; Frq=1000000.0/x/2; void timer0() interrupt 1 { TH0=~Frq/256; TL0=~Frq%256; Frq_Output=~Frq_Output; } void main() { uchar i; IE=0x82; TMOD=0x01; TR0=1; while(1) { Get_AD_BCD_Result(); for(i=0;i<4;i++) { P2=DSY_POSITION_Table[i]; P0=Display_Buffer[i]; DelayMS(1); } } } 具体程序如下: 程序1 #include #include #include #define uchar unsigned char #define uint unsigned int sbit CS=P1^0; sbit CLK=P1^3; sbit DIO=P1^4; sbit Frq_Output=P3^0; uint Frq; unsigned char i=0 , x =0 , y = 0 ; uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; uchar DSY_POSITION_Table[4]= {0x08,0x04,0x02,0x01}; uchar Display_Buffer[4]={0x00,0x00,0x00,0x00}; void DelayMS(uint x) { uchar i; while(x--) for(i=0;i<120;i++); } uchar Read_AD() { uchar i,x=0; //ADC0832初始化 CS=0; CLK=0; DIO=1; CLK=1; CLK=0; DIO=1; CLK=1; CLK=0; DIO=0; CLK=1; CLK=0; DIO=1; for(i=0;i<8;i++) { CLK=1; CLK=0; x=(x<<1); if(DIO ==1) x = x | 0x01; } for(i = 0 ; i<8 ; i++) { y = y>>1; if(DIO ==1) y = y | 0x80; CLK = 1 ; CLK = 0 ; } CLK=1; DIO=1; CS=1; } void Get_AD_BCD_Result() { uint x=Read_AD()*30; Frq=1000000.0/x/2; Display_Buffer[3]=DSY_CODE[x/1000]; Display_Buffer[2]=DSY_CODE[x/100%10]; Display_Buffer[1]=DSY_CODE[x%100/10]; Display_Buffer[0]=DSY_CODE[x%10]; } void timer0() interrupt 1 { TH0=~Frq/256; TL0=~Frq%256; Frq_Output=~Frq_Output; } void main() { uchar i; IE=0x82; TMOD=0x01; TR0=1; while(1) { Get_AD_BCD_Result(); for(i=0;i<4;i++) { P2=DSY_POSITION_Table[i]; P0=Display_Buffer[i]; DelayMS(1); } } } 程序2 #include #include #include #define uchar unsigned char #define uint unsigned int sbit CS=P1^0; sbit CLK=P1^3; sbit DIO=P1^4; sbit Frq_Output=P3^0; uint Frq; uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; uchar DSY_POSITION_Table[4]= {0x08,0x04,0x02,0x01}; uchar Display_Buffer[4]={0x00,0x00,0x00,0x00}; void DelayMS(uint x) {uchar i; while(x--) for(i=0;i<120;i++); } uchar Read_AD() { uchar i,d=0; CS=0; CLK=0;DIO=1; CLK=0;DIO=1; CLK=1;DIO=0; CLK=0;DIO=0; CLK=1;DIO=1; CLK=0;CLK=1; for(i=0;i<8;i++) { CLK=0;d=(d<<1)|DIO;CLK=1; } CS=1; return d; } void Get_AD_BCD_Result() { uint d=Read_AD()*30; Frq=1000000.0/d/2.0; Display_Buffer[3]=DSY_CODE[d/1000]; Display_Buffer[2]=DSY_CODE[d/100%10]; Display_Buffer[1]=DSY_CODE[d%100/10]; Display_Buffer[0]=DSY_CODE[d%10]; } void T0_INT() interrupt 1 { TH0=-Frq/256; TL0=-Frq%256; Frq_Output=~Frq_Output; } void main() { uchar i; IE=0x82; TMOD=0x01; TR0=1; while(1) { Get_AD_BCD_Result(); for(i=0;i<4;i++) { P2=DSY_POSITION_Table[i]; P0=Display_Buffer[i]; DelayMS(1); } } } 4.5 功能调试 加载程序,后仿真实现: 图4.6 RV1=300欧时数码管显示 图4.7 RV1=300欧时输出波形 图4.8 RV1=740欧时数码管显示 图4.9 RV1=740欧时输出波形 结束语 此次课程设计总共发费两周时间,经过自己的努力终于完成设计任务。本次课程设计我做的是应用ADC0832调节频率输出,在这之前我没有使用过ADC0832正好借此机会学习它的使用方法。在显示部分,本来为了简单就直接用数码管显示。在开始的准备资料阶段,我在网上找来了ADC0832的中文用户手册,学着看时序,写驱动。不过还是遇到了困难,对于数据通道的选择我不是很明白。又在网上论坛找来驱动程序一行一行对比着来看。看着硬件电路简单,原理也简单想来设计应该没难点,可是在定时器装初值产生中断时又遇到困难。没有弄清楚变化电压和频率变化一一对应的关系,不知道怎么装初值产生合理的中断。自己想不明白就在网上看人家是怎么写的。Frq=1000000.0/x/2;这句话网上的解释是频率延时,x是采集数据,除以2我想了好久都没明白,后来求助同学,同学提醒是产生了两个中断才是一个周期。原来我一直盯着一行想忘了后面还有中断取反产生高低电平,所以不能很好的理解程序的思想。课程设计结束,中间有很多问题是以前就知道自己有欠缺,比如写程序能力差;还暴露了其他问题,在新学一个芯片或器件时看时序不能很好的把握其中的意思很浅显的东西也会看不太明白,这个提醒我数电已经忘得差不多了学过的东西没能好好的运用起来。写程序是一个细心严谨的过程,期间有自己的努力,有同学老师的帮助。总算把程序写完整。通过这次课程设计,我还是学到了一些东西的。 参考文献 [1] 李光飞. 单片机C程序设计实例指导[M]. 北京:北京航空航天大学出版社, 2005 [2] 楼然苗. 51系列单片机设计实例[M]. 北京:北京航空航天大学出版社, 2003 [3] 李光飞. 单片机课程设计实例指导[M]. 北京:北京航空航天大学出版社, 2004 致谢 感谢邵阳学院提供这次课程设计的机会,感谢老师为这次课程设计提供的各种资料。感谢宿舍同学在我制作过程中给我的各种帮助,感谢贴吧网友的热心回复。本次设计是在彭森老师精心指导和大力支持下完成的。彭老师治学严谨对课程设计严格要求,非常耐心的帮我改正论文写作中的错误,对待论文格式的认真态度让我敬佩不已啊。是老师的严要求才让论文完成得这么好。课程设计期间,还要感谢谢同学给我更改格式上的错误。下载本文