简易多功能计数器(两种方案)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2008年F题简易多功能计数器
本文论述了电子计数式简易多功能计数器的原理、设计、应用及误差特性。
以ATmega128单片机为控制核心,由FPGA模块、键盘输入模块、液晶显示模块、
温度测量模块等功能模块组成,实现了周期
随着科学技术的发展,频率和时间测量的意义已日益显著,不仅与人们日常生活息息相关,而且在当代高科技中更是显得重要。
可编程逻辑器件和EDA计数给今天的硬件系统设计者实现了强而有力的工具,使得电子系统设计方法发生了质的变化。
本文论述了电子计数式简易多功能计数器的原理、设计、应用及误差特性。
本计数器以ATmega128单片机为控制核心,由FPGA模块、键盘输入模块、液晶显示模块、温度测量模块等功能模块组成,实现了周期、频率、时间间隔的测量等功能。
在设计方法上,由传统的“电路设计—硬件搭试—焊机”的传统方式到“功能设计—软件模拟—下载”的电子自动化模式,以软件设计为主,硬件设计为辅的指导思想,将复杂硬件软件化,从而大大提高了系统设计的灵活性和稳定性。
关键字:电子计数式,测量精度,可编程逻辑器件,AVR单片机,门控信号
Multi-function Counter
ABSTRACT
The FPGA(Field Programmable Gate Array) provides a fast, accurate and flexible solution for digital system design. This paper discusses the design flow, scheme selection, and error control and analysis of a multi-function counter. Based on ATmega128 as the microcontroller, it consists of the FPGA module, keyboard modules, liquid crystal display (LCD) modules, temperature measurement module etc. This system can be applied in the period, frequency, interval measurements. As for the design methods, the "functional design - software simulation - Download" electronic automatic mode takes the place of the traditional "circuit design - hardware test ride - welder" methods. It mainly depends on the EDA Tools, supplemented by the hardware design and in this way it simplifies the hardware design, greatly improving the flexibility and stability of the system.
Key words: Frequency Meter, Period Meter, Counter, Measurement Accuracy, FPGA, AVR
目录
正文
1.1 设计要求
1.1.1 基本设计要求
----------------------------------------------------------------------1
1.1.2 发挥设计要
-------------------------------------------------------------------------1
1.2 测量原理
1.2.1频率测量原理
-----------------------------------------------------------------------1
1.2.2 时间间隔
-----------------------------------------------------------------------------1
1.2.3 系统测量原
--------------------------------------------------------------------------2
1.3 系统总体方案
1.3.1 系统总体方案的比较与
----------------------------------------------------------2
1.3.2 系统总框图
--------------------------------------------------------------------------3
1.4 各模块硬件电路实现
1.4.1 FPGA模块
---------------------------------------------------------------------------3
1.4.1.1 频率测量
---------------------------------------------------------------------------3
1.4.1.2时间间隔测量
---------------------------------------------------------------------4
1.4.1.3 其他
---------------------------------------------------------------------------------5
1.4.2信号预处理
---------------------------------------------------------------------------6
1.4.3 AD采样测幅值
----------------------------------------------------------------------7
1.4.4 温度测量模块
---------------------------------------------------------------------
--7
1.4.5 键盘输入模块
-----------------------------------------------------------------------7
1.4.6 液晶显示模块
-----------------------------------------------------------------------7
1.4.7 语音报时模块
-----------------------------------------------------------------------7
1.4.8 自制电源
-----------------------------------------------------------------------------7
1.4.9浮点数除法运算
---------------------------------------------------------------------8
1.5 系统软件设计
2.5.1 主程序流程图
----------------------------------------------------------------------8
2.5.2 界面设计
----------------------------------------------------------------------------9
1.6 测试与结果分析
2.6.1 参数测量结果
-----------------------------------------------------------------------10
2.6.2 误差与结果分析
--------------------------------------------------------------------1 1
1.7设计总结
----------------------------------------------------------------------------------12
1.8参考资料
----------------------------------------------------------------------------------12
附录
1.1元件清单
----------------------------------------------------------------------------------13
1.2电路设计原理图及相关仿真结构
--------------------------------------------------13
1.3源程序代码
---------------------------------------------------------------------
----------13
正文
1.1设计要求
1.1.1 基本设计要求
(1)具有测量周期、频率、时间间隔的功能;
(2)可以用键盘选择上述三种功能;
(3)周期、时间间隔测量:0.1mS~1S,误差≦0.1%;频率测量:1Hz~200KHz,误差0.1%;
(4)能够显示至少六位数码,并自制计数器电源
1.1.2 发挥设计要求
(1)周期、时间间隔测量:1µS~10S,误差≦0.1%;频率测量:0.01Hz~10MHz,误差≤0.1%;
(2)可以记忆10个历史测量数据,且能够随时查看;
(3)实现语音报数功能,并且显示被测信号的峰值;
(4)其他(如温度、时间等功能)。
1.2测量原理
1.2.1 频率测量原理
原理一般可分为模拟法和电子计数法两种,电子计数法具有测量精度高、速度快、自动化程度高、操作简单等优点而应用更为广泛。
图1—频率测量原理图
示,由晶振分频及门控制电路得到具有固定宽度Ts的方波脉冲作为门控信号,加到闸门的控制端,控制闸门开、闭的时间。
设被测信号频率为Fx,¬¬,门控信号持续时间为TS,计数器计数为N。
测频时,将计数器置零,待门控信号来到后打开闸门,允许被测脉冲通过,计数器开始计数,只到门控信号结束,闸门关闭,停止计数。
此时Fx=N/TS。
可见,此种测量方法中门控信号的选取是关键,门控信号决定了所测频率的准确程度,如测量低频信号时,在门控信号持续的时间内计数器计数较小,测量误差较大。
1.2.2 时间间隔测量原理
时间间隔测量可分为连续时间测量和单次测量。
连续测量用于周期信号的多次测量,然后通过取平均值以达到较高的测量精度;单次测量就是以随机的一次测量为基础,其测量原理图1——2所示:
图1—周期测量原理图
设量化时钟的频率为T0,待测脉冲上升沿到来时量化时钟的初始计数为M,下一次待测脉冲上升沿到来时量化时钟技术为M,T1、T2为待测脉冲上升沿与下一个量化时钟脉冲上升沿之间的时间间隔,则时间间隔为T x=(N-M)*T0+T1-T2。
这种测量方法是测量T x内的时钟量化时钟个数,对于高频信号而言,T x时间内计数器计入量化时钟个数较小,测量误差较大。
此种测量方法以被测信号本身作为门控信号,通过测量门控信号中的量化信号个数得出时间间隔。
1.2.3 本系统测量原理的选择
比较以上两种测量方法,前者(以下简称测频法)是在给定的闸门时间内测量被测信号的脉冲个数,进行换算得出被测信号的频率。
测频法的测量精度取决于闸门时间和被测信号频率。
当被测信号频率较低时将产生较大的误差,除非闸门时间取得很大(即要求晶振分频倍数大,使门控信号能够达到足够小的频率)。
后者(以下简称测周法)是以给定信号为门控信号,通过测量门控信号时间内通过的量化信号的个数换算出时间间隔的。
测周法的测量精度取决于被测信号的周期和计时的精度,当被测信号频率较高时,计时精度的要求就很高了。
实际上,测周法和测频法都存在一个字的技术误差问题:测频法存在门控信号内一个被测信号的脉冲个数误差,测周法存在一个被测信号内量化信号脉冲个数误差。
为了提高系统测量精度,我们采用任何一种方法测量都应该保证计数个数N 足够大。
因此,对于周期测量分为高频档和低频档。
低频信号直接测量,高频信号则先通过分分频器分频,转化为低频信号后,按照低频档的方法测量。
对于频率测量,依然分成高频、低频两档。
对于低频信号我们采去测周法,然后根据公式f=1/T,计算出低频频率。
由于单片机做浮点运算的精度有限,在编写单片机程序时,还应该注意采取有效算法控制运算精度。
1.3系统总体方案
1.3.1系统总体方案的比较与论证
方案一:传统51单片机和集成计数器。
传统51单片机功能简单,易于控制而且操作方便,但是工作速度慢,对于题中高频信号的测量会引起致命误差,而且传统51单片机片内资源不丰富,I/O口数量很少,需要通过8155扩展端口。
对于集成计数器,测量高频信号时,计数值可达100000000,以10位计数器(74LS160)为例,需串联8个,单片机的外围电路非常复杂,同时复杂的外接电路会影响整个系统的响应时间,导致很大误差。
方案二:高性能AVR单片机与FPGA。
高性能AVR单片机是在传统51单片机的基础上发展起来的,它继承了传统51单片机的优点,并在此基础上有所提高。
AVR单片机凭借高速、低功耗、丰富的片类资源等强大功能得到了广泛的应用。
通过对FPGA的编程将复杂而庞大的外部硬件计数电路软件化,FPGA内自带的50MHz有源晶振保证了整个系统的响应速度,系统稳定性得到提高,误差减小。
1.3.2 系统总方框图
如下图所示,FPGA完成测量功能,AVR控制液晶显示、温度测量、语音报时、峰值测量、键盘输入等功能。
图3—系统总框图
1.4 各模块硬件实现
1.4.1 FPGA部分
FPGA部分由频率测量模块、周期/时间间隔测量模块、SPI通信模块,PLL等子模块组成。
1.4.1.1 频率测量模块
图4—频率测量模块
频率测量模块由分频模块、门控模块,BCD计数模块和数据锁存模块组成。
其中分频模块将FPGA开发板的50M的时钟分频为2Hz门控时钟。
门控模块收门控时钟的上升沿,对BCD计数器的使能(enable)、清零(clr)和数据锁存(lck)信号的时序进行控制图5所示。
值得注意的是,本频率测量模块使用的BCD计数器而不是普通二进制计数器。
BCD 码很大程度上方便了单片机将其转换成字符型数据,最终显示在LCD上。
我们发现,二进制码转BCD码的算法较为复杂,同时占用的FPGA的片内资源也较多,故直接采用BCD计数方法。
图5—频率测量时序图
1.4.1.2 周期/时间间隔测量模块
周期测量使用两个状态机(主状态机和sig_sel状态机)实现。
对于低频信号(signal_x),我们直接计算其一个周期包含的量化时钟的数目。
对高频信号,将其通过分频器分频后再计算包含的量化时钟的数目。
由sig_sel 状态机选择被量化的信号。
(如图6所示)
为达到精度0.01%的要求,每个signal时钟需包含大于10000个量化时钟。
因此,我们对周期小于100us的信号进行1000倍分频。
图6—自动转量程原理图
时间间隔测量原理与周期测量相同。
区别在于时间间隔测量为单次测量,周期测量为连续测量。
单脉冲周期无频率而言,故不能经过分频器(sig_sel始终为0)。
为区别周期测量和时间间隔测量这两种模式,本模块引入一个模式选择信号(mode)当mode=1时为侧周期模式,当mode=0是为测时间间隔模式。
主状态机:
测量一次上图中signal信号周期需要用3个signal的方波的周期。
每一个
signal周期对应一种状态,每种状态下执行不同的操作。
状态转换图以及各状
态的功能如表1所示。
表1—状态机功能
*设置hold状态计数器和idle状态计数器的目的是避免出现被测信号的频率过
低而又被1000倍分频导致的电路所死(长时间处于idle或hold状态)的情况。
sig_sel状态机:
sig_sel状态用于控制被测方波是否经过分频,起到了扩大量程和提高测量精度
的作用。
sig_sel两个状态的功能如下表2所示
表2—功能表
sig_sel状态机的verilog描述:
always @ (posedge clk)
begin
if(rst==0 || mode==0)
sig_sel<=0;
else if (cnt>=1_0000_000 || cnt_hold>=1_0000_000 || cnt_idle>=1_0000_000)
sig_sel<=0;
else if (curr_s==hold && sig_sel==0 && cnt<1_0000)
sig_sel<=1;
else
sig_sel<=sig_sel;
end
计数器:
周期测量同时使用BCD码计数器和二进制计数器。
二进制值用于状态的判断和转换。
BCD码方便了单片机处理和显示数据,这与频率测量模块相同。
图8—ATmega128与FPGASPI通信
本接口模块中所需实现的逻辑功能是,从机FPGA在主机ATmega128提供的CLK 时钟信号下,按照SPI接口规范,按照SPI时序图的规范接受数据,然后执行测量对象选择、液晶显示等操作。
其工作流程如下,ATmega128通过MOSI向FPGA 发送数据(该数据低八位储存地址信息,高八位储存数据信息,FPGA对地址译码,选择合适的数据输入端),AVR在load端产生下降沿,FPGA将相应数据读入寄存器中,当CS=0,load=1的情况下,在每一个SCLK时钟的上升沿,移位寄存器的数值左移一位。
数据就通过MISO送到MCU中。
图9—SPI时序图
(2)量化时钟周期的选择
合适的量化时钟周期可以简化运算的复杂程度,提高测量效率。
我们选择10ns
为量化时钟信号,计算简单,而且保证了测量精度。
1.4.2信号预处理
系统中计数是以上升沿或下降沿为标准的,因此一般信号需通过电压比较器整形为方波信号。
FPGA中的计数器是边沿触发而不是电平触发,整形后波形边沿的
陡峭程度显得非常重要。
对于方波信号,我们应根据实际情况整形或者直接通过稳压管稳压后测量相关参数。
对高频信号,我们采用精密TTL比较器MAX941,该比较器具有低功耗、超高速(可达10ns)等优点,可以满足本系统中对高频信号的整形要求。
对于低频信号,经比较器整形后,由于采样速度快,进过比较处理后边沿的陡峭程度受到很大制约,在某种程度上影响了FPGA中计数器对这种非陡峭边沿的识别,从而导致测量中的计数误差。
对于低频信号,我们采取可以外接其它整形电路(如施密特整形,滞回比较器整形等)以弥补MAX941的不足。
1.4.3 AD采样测幅
幅度测量采用ATmega128自带的AD转换器,对被测信号(初始信号)对此采样,每次采样与前一次采样比较,保留最大采样值,即可换算出信号的峰值。
显然,对于高频信号,由于AD转化器采样速度的限制,所测峰值误差较大。
1.4.4 温度测量模块
方案一:采用热电偶或者热敏电子作为感温元件,但热电偶需要冷端补偿,电路设计复杂,热敏电阻虽然精度较高,但需要标准稳定的电阻匹配才能使用,而且重复性、可靠性都比较差。
方案二:采用集成温度传感器DS18B20,该传感器结构简单,不需要外接电路,数据传输用one—wire总线,可用一根I/O数据线既供电又传输数据,在-10~+85℃范围内精度为±0.5℃,且分辨率较高,重复性和可靠性好。
显然,我们采用方案二。
1.4.5键盘输入模块
键盘输入有独立键盘和矩阵键盘两种选择。
对于单片机最小板自带的8个独立按键而言完全可以实现本系统的要求。
但是对于同样的端口,矩阵键盘多了一倍的按键,易于通过多余的按键实现扩展功能的手动控制,例如,单片机接受到某一按键信号后会执行温度测量并且显示温度的程序,接受到另一按键信号会执行峰
值测量并显示的程序。
本系统中按键的设置如下:选择测量对象?周期,频率,时间间隔;选择需储存记忆数据;是否显示峰值;是否温度测量;是否语音报数;是否返回主界面;返回上一页等。
1.4.6 液晶显示模块
2402液晶模块,24行*2列字符显示,并行8/4数据通信,可以满足本系统中至少显示六位的要求。
我们假期已经调过液晶显示的模块,利用C语言模块的可移植性,直接将模块移植过来,根据实际情况更改数组内容,即可实现测量参数的显示。
1.4.7 语音报数模块
语音报时使产品与使用者进行良性的互动,大大提高了本测量系统的竞争能力。
我们选用智能型640秒语音录放模块实现语音报数功能。
该模块由麦克风、喇叭、语音芯片及应外围电路组成。
该模块具有话筒录音、线路录音、直接驱动喇叭、支持按键和三线串口控制模式、断点信息不丢失等特点。
对于本计数器中的报数功能,我们可以按照如下操作:ATmega128单片机通过SPI外串行总线端口给语音模块发送FB+XXH(定时录音模式),然后通过麦克风将数据依次录音,存在合适的地址中,方便播放时寻找合适音频信号。
单片机将FPGA测得的数据按照相对应的规律,找到语音模块中的地址,并发送FCH+XXH(播放模式),从而实现语音报数功能
1.4.8自制电源
本系统中FPGA、ATmega128、电压比较器等器件都需要合适的直流电源供电,因此我们自制了相应的直流电源。
如下图所示,将输出的220V交流信号经变压器降压,整流桥整流,电容滤波,7805、7905等集成稳压器稳压,从而得到满足相应要求的直流电源
图10—电源原理图
1.4.9浮点数除法运算的实现
测频法存在门控信号内一个被测信号的脉冲个数误差,对于高频信号而言,门控信号内通过的被测信号脉冲的个数足够大,一个脉冲的缺失,对测量结构不产生影响;对低频信号而言,门控信号内通过的被测信号脉冲个数很小,一个脉冲的缺失会引起很大的误差,故对低频信号我们采用测周期的方法,通过求倒数换算出周期。
求倒数换算周期,浮点数的除法运算及浮点数显示是本设计中的两大难点。
对于0.1%的精度要求,不同频率范围内的周期求倒数后,小数点后需精确到的位数要求不一样,我们通过寻求第一位有效数字的位置,推测出小数点的位置,(如下表所示)根据相应位数精确度的要求截断无效数据,即可计算出误差范围内结果。
对于浮点数的显示,鉴于八位单片机处理极限是65536的数据,我们将浮点数依次扩大10000倍,取出小数点后的高四位按照整数方法显示,类似这样的操作取出小数位低四位并且显示.
1.5 系统软件设计
1.5.1 主流程图
图7—周期测量模块
1.4.1.3 其他
(1)SPI通信
本测量系统中不可避免地要实现FPGA和ATmega128间的通信。
我们可以选择UART协议、I2C协议、SPI协议。
其中串行外接口设计SPI(Serial Peripheral Interface)的实质是同步串行总线接口,由于其接线简单,使用起来非常方便,广泛应用于各种外设与单片机之间的通信。
本系统就是通过SPI实现ATmega128和FPGA之间通信的。
SPI总线有四根组成:串行时钟线(SCK)、主机输出/从机输入线(MOSI),从机输入线(MISO),从机选择线(SS)。
1.5.2 用户界面设计
随着科学技术的日益发展,很多测量工具除了提供相应的测量功能意外,还友好的人性化的界面向导,这不仅有利于引导客户进行正确的操作,也有利于扩大测量工具本身的潜在市场。
因此我们设计了友好的人机交换界面(如“欢迎使用本计数器”“您可以选择1频率测量2周期测量3时间间隔测量”“16键返回主页面”“如果您想储存此数据,请按5,否则按6”)。
用户可以根据自己的需要输入相应的按键,实现相应的功能。
图12—用户界面方框图
1.6 测试与结果分析
1.6.1 参数测试结果
考虑到不同基准信号本身有着不同的精确程度,我们选择的测试信号分别为EDA 实验箱(ZY11EDA13BE)中信号、高频信号发生器(YB1051)、FPGA内部处理产生信号(50M有源晶振,经过内部PLL两倍频,再分频)。
(1)周期测量数据
(2)频率测量数据
前两组为EDA中信号,后两组为FPGA内部分频引出后在接入待测端口
时间间隔测量
对于时间间隔测量部分,受到实验室测量设备的限制,暂无数据。
据理论分析,而且时间间隔测量和周期测量共用一个模块,推测误差范围也应该满足要求。
峰值测量数据
分别测量方波,三角波,正弦波的峰值入下表所示:
1.6.2 误差与结果分析
(1)周期测量误差与结果分析
考虑到实验箱信号本身的精确程度,我们也选择了FPGA50MHz有源晶振经锁相环倍频、分频器分频后引出的信号作为测量信号,以作为参考。
有表格一分析可知:EDA试验箱中信号测量数据与实际数据存在较大差异,而FPGA引出的信号测量数据与实际数据完全一致。
由于FPGA中有源晶振经PLL倍频锁定后,输出的信号具有和固定基准信号同样的频率稳定性,我们有理由相信是EDA实验箱中先好自身存在误差,本计数器的周期测量功能成功实现。
另外,对EDA中高低频信号的测量误差进行分析可以证实原理中提到的“对于周期测量,高频信号产生的误差比低频信号产生的误差大”的观点。
(3)频率测量误差与结果分析
与周期测量类似,我们采用两种信号作为测试信号。
由表4中的分析数据可知,无论对于方波还是正弦波,频率测量的误差满足设计要求。
我们顺利的完成了关于周期的所有基本和发挥的设计要求。
对于FPGA内部产生的信号,其精确度近似为100%。
高频信号发生器中产生的信号残生较大误差的原因是,高频信号发生器中所示的信号精确度很小,相对于我们所测得的精确到小数点后三围甚至六位而言,误差是不可避免的。
(4)峰值测量误差与结果分析
AD对此采样,每次采样数据保留最大采样数据,理论上可以采到峰值并且显示。
但实际对于高频信号而言,由于信号自身变化速度很快,甚至超过了AD采样的速度,有可能在短时间内采不到峰值点的数据,而使得测量结果偏小。
分析表5中数据可得以下结论:对于方波信号,只存在两中采样情况,因此高频或低频多容易猜到峰值电压;对于正弦波、三角波信号,存在多种采样情况,采到峰值的可能性随频率的增高而减小,因此低频时交易测得峰值信号,高频测量误差很大。
1.7 设计总结
经过四天三夜的奋战,我们完成了题目基本要求和发挥要求,但由于时间和硬件资源的限制,个别指标做的不是非常完善。
首先,我代表我们小组感谢本次竞赛的主委会和全体评审老师以及我们的辅导老师,谢谢你们给我们一个提高和展现自己的舞台,让我们在以后的人生中更加自信和坚定,另外也要感谢美信公司给我们提供了不少高质量芯片,使我们的电子设计进行得更加顺利。
回想这四天三夜紧张生活,短暂而充实,从焊板到编程、从示波器上波形的跳动到稳定,从手动测量到自动测量……当我们看着液晶显示屏上显示出精确的数据时,那种喜悦是无法用语言形容的。
有付出,所以有收获,就我们组而言,大家在许多方面都有了明显的进步和收获,无论是拼搏精神还是团队精神都是我们这一辈子的精神财富。
所以不管结果如何,我们都会继续发扬这种精神,不断提高和完善自己。
坚定不移地在电子设计这条路上努力,奋斗。
1.8参考文献
[1] 谭丙煜. 怎样撰写科学论文. 沈阳:辽宁人民出版社,1982:59
[2] 童诗白华成英《模拟电子技术基础》高等教育出版社,2000:12
[3] 吴继华王诚《Verilog HDL 设计与论证》人民邮电出版社,2006:8
[4] 夏雨闻《数字系统设计教程》北京航空航天大学出版社,2003:1
[5] 洗进《Verilog HDL数字控制系统设计实例》中国水利出版社,2004:7
[6] 袁文波 <<FPGA应用开发从实践到提高>> 中国电力出版社 2007
[7] 刘韬, 楼兴华编著<<FPGA数字电子系统设计与开发实例导航>> 北京人民邮电出版社 2005
附录
表6—元件清单
附录三:电路设计原理图及相关仿真图
附录四:部分源程序代码AVR部分源代码
/*====================================================== 头文件名:ad.h
功能:AD转换
======================================================*/ uchar volatge[10];
uint adc() //读取AD转换结果的2进制值
{
uint ad_data;
DDRF=0X00;
PORTF=0X00;
ADMUX=(0X40|BIT(MUX4));
ADCSRA=0x80;
ADCSRA|=BIT(ADSC);
while(!(ADCSRA&BIT(ADIF)));
ad_data=ADCL;
ad_data|=(uint)(ADCH<<8);
return ad_data;
}
convert(uint data) //读取AD转换结果的2进制值
{
voltage[4]=data%10+'0';
data=data/10;
voltage[3]=data%10+'0';
data=data/10;
voltage[2]=data%10+'0';
data=data/10;
voltage[0]=data+'0';
}
//======================================================
/*====================================================== 头文件名:DS18B20.h
功能:DS18B20驱动程序
======================================================*/
//===================================================== // 宏定义部分,如果要使用本头文件,直接修改此部分即可
//===================================================== #define CLR_DIR DDRC&=~BIT(0)
#define SET_DIR DDRC|=BIT(0)
#define CLR_OP PORTC&=~BIT(0)
#define SET_OP PORTC|=BIT(0)
#define CHECK_IP (PINC&0X01)
uchar temperature[10]=" ";//读取温度缓存区
//=====================================================
// 延时函数,此延时函数能满足DS18D20的时序要求
//=====================================================
void delay_1us(void) //1us延时函数
{
asm("nop");
}
void delayus(unsigned int n) //N us延时函数
{
unsigned int i=0;
for (i=0;i<n;i++)
delay_1us();
}
//=====================================================
// DS18D20复位函数
//===================================================== void reset()
{
SET_DIR;
SET_OP;
CLR_OP;
delayus(480);
SET_OP;//要先把他置1,DDRNX清0,这样才有上拉,不然是高阻态CLR_DIR;
delayus(20);
while(!CHECK_IP);
SET_DIR;
SET_OP;
delayus(140);
}
//=====================================================
// DS18D20写数据/命令
//===================================================== void writebyte(uchar dat)
{
unsigned char m;
for(m=0;m<8;m++)
{
CLR_OP;
if(dat&0X01)
{
SET_OP;
delayus(70);
}
else
{
CLR_OP;
delayus(70);
SET_OP;
}
dat>>=1;
}
}
//===================================================== // DS18D20读数据
//===================================================== uchar readbyte()
{ uchar i,dat;
for(i=0;i<8;i++)
{
dat>>=1;
SET_DIR;
CLR_OP;
SET_OP;
CLR_DIR;
if(CHECK_IP==1)
dat|=0X80;
delayus(50);
}
return (dat);
}
//===================================================== // DS18D20初始化
//===================================================== config()
{
reset();
writebyte(0xCC);
writebyte(0x4E);
writebyte(0xFF);
writebyte(0xFF);
writebyte(0x7F);//设置精度为1/16摄氏度
}
//===================================================== // 读取温度,并转换成BCD码,显示在tempre数组中
//===================================================== void read_temper()
{
uchar lsb=0,msb=0,temper=0;//定义变量的时候记得赋初值float backbit=0;//小数点后的数值×1000
unsigned int temper1;
reset();//复位
writebyte(0xCC);//跳过序列号
writebyte(0x44);//开启温度转换
reset();//复位
writebyte(0xCC);//跳过序列号
writebyte(0xBE);//开始ds18b20的寄存器
lsb=readbyte();//读温度寄存器的低8位
msb=readbyte();//读温度寄存器的高8位
backbit=(lsb&0x0F)*625;//获取温度的小数部分
temper1=backbit;//将浮点型数据转化为int型
lsb=(lsb>>4)&0x0F;//获取温度的整数部分
msb=(msb<<4)&0xF0;
temper=(msb|lsb)%0x7f;
//温度缓存区
temperature[0]=(temper%100)/10+'0';
temperature[1]=temper%10+'0';
temperature[2]='.',
temperature[3]=temper1/1000+'0';
temperature[4]=(temper1%1000)/100+'0';
temperature[5]=(temper1%100)/10+'0';
temperature[6]=temper1%10+'0';
}
/*================================================= 头文件名:2402.h
功能:LCM2402液晶的驱动程序
==================================================*/ #include <iom128v.h>
#include <macros.h>
#define uchar unsigned char
#define uint unsigned int
//BGHSDGHDSGH
#define LCM_rs 0
#define LCM_wr 1
#define LCM_en 2
#define DDR_LCM_CONTROL DDRA
#define DDR_LCM_DATA DDRB
#define PORT_LCM_CONTROL PORTA
#define PORT_LCM_DATA PORTB
void LCM_delay(uint ms)
{
uint i,j;
for(i=0;i<ms;i++)
{
for(j=0;j<1141;j++);
}
}
void LCM_delay1(uint time) //delay about 1.25us
{ uint i,j;
for(i=0;i<time;i++)
for(j=0;j<10;j++);
}
void LCM_write_cmd(uchar cmd)
{
PORT_LCM_CONTROL&=~BIT(LCM_rs);
PORT_LCM_CONTROL&=~BIT(LCM_wr);
PORT_LCM_DATA=cmd;
PORT_LCM_CONTROL|=BIT(LCM_en);
LCM_delay1(2);
PORT_LCM_CONTROL&=~BIT(LCM_en);
}
void LCM_write_dat(uchar dat)
{
PORT_LCM_CONTROL|=BIT(LCM_rs);
PORT_LCM_CONTROL&=~BIT(LCM_wr);
PORT_LCM_DATA=dat;
PORT_LCM_CONTROL|=BIT(LCM_en);
LCM_delay1(2);
PORT_LCM_CONTROL&=~BIT(LCM_en);
}
void LCM_initial()
{
DDR_LCM_DATA=0XFF;
DDR_LCM_CONTROL|=BIT(LCM_rs)|BIT(LCM_wr)|BIT(LCM_en); PORT_LCM_CONTROL&=~BIT(LCM_wr);
LCM_write_cmd(0X38);
LCM_delay(5);
LCM_write_cmd(0X01);
LCM_delay(5);
LCM_write_cmd(0X0C);
LCM_delay(5);
LCM_write_cmd(0X06);
LCM_delay(5);
}
void LCM_shift_left(uchar k)
{
uchar i;
for(i=0;i<k;i++)
{
LCM_write_cmd(0X18);
LCM_delay(500);
}
}
void LCM_write_line(uchar pos,uchar data[])
{
uchar i;
LCM_write_cmd(0X80+pos);
LCM_delay1(2);
for(i=0;data[i]!='\0';i++)
{
LCM_write_dat(data[i]);
LCM_delay1(2);
}
}
/*======================================================= 头文件名:key.h
功能:4*4矩阵键盘驱动程序
=======================================================*/ //矩阵键盘的扫描程序
//键值保存在全局变量key中
uchar scancode[4]={0XF7,0XFB,0XFE,0XFD};//扫描
uchar keyboard()
{
uchar i,key=16;
DDRC=0X0F;
PORTC=0XFF;
for(i=0;i<4;i++)
{//start for
PORTC=scancode[i];
LCM_delay(1);
switch(PINC)
{//start switch
case 0XEE:key=0;break;
case 0XDE:key=1;break;
case 0XBE:key=2;break;
case 0X7E:key=3;break;
case 0XED:key=4;break;
case 0XDD:key=5;break;
case 0XBD:key=6;break;
case 0X7D:key=7;break;
case 0XEB:key=8;break;
case 0XDB:key=9;break;
case 0XBB:key=10;break;
case 0X7B:key=11;break;
case 0XE7:key=12;break;。