数据采集终端的设计

摘要:本论文基于AT89S52单片机,设计了一个数据采集终端控制器,旨在巩固《微机原理及接口技术》课程所学理论知识,并初步了解单片机应用系统设计与调试方法。硬件设计采用了AT89S51处理芯片和8255A接口芯片,实现了数码管显示、矩阵键盘输入、温度采集和串口通信等功能。软件设计包括开机自检、温度数据采集、时间和日期显示、温度报警、键盘操作和上下位机通信等功能。通过详细的硬件原理图设计和软件功能实现,本论文提供了一个完整的数据采集终端控制器方案。

数据采集终端的设计

1设计目的

  通过单片机应用产品的设计与调试过程,巩固《微机原理及接口技术》课程所学理论知识,初步了解单片机应用系统设计与调试的方法。

2设计任务

  设计一个以AT89S52单片机为核心的数据采集终端控制器。
  1. 设计硬件系统原理图(最好采用最小系统,不要扩展8255)。硬件组成,以AT89S52单片机为核心,系统有8位数码管显示器、指示灯、蜂鸣器等用于时间、数据显示和告警等输出;44矩阵键盘(含数字键0~9及功能键)或独立式按键用于切换显示内容、调整参数等操作;串行接口用于单片机与上位机(PC机)的通信;A/D转换接口(ADC0809)实现对2路(及以上)温度的检测,设选用的线性温度传感变送器将检测的-20℃+65℃温度变换为05V电压信号,经ADC0809转换后变换为温度。
  2.在硬件基础上,设计软件实现下列功能,并在实验板上模拟调试实现控制器的功能。
  (1)开机自检,检查相关接口及数码管显示器、指示灯、蜂鸣器等外设是否正常,消除窜显和显示亮度不均匀。
  (2)以一定的时间间隔采集温度数据,并通过标度变换转换为实际的温度值(整数或含小数)。对数字量有合适的数字滤波方式保证数据稳定(选做)。
  (3)平时数码管以一定的时间间隔交替显示时间、日期(2000~2099年,选做)、温度,显示格式自己定义(如显示温度时包括温度值、温度单位“℃”,温度值可以只有整数或小数点后1位)。
  (4)具有温度报警功能,当温度超出设定范围(太低或太高)可以通过蜂鸣器、指示灯报警,数码管显示相应通道。
  (5)通过键盘切换显示内容、调整时间、设置报警参数(选做)。设定参数过程有合适的方式指示当前可修改的内容。对开关量输入进行软件消抖动处理,参数的设定有检错处理,如:小时不能超过23,日期中每月最大天数、闰年等。按键按下时回馈短促的按键音(选做)。参数设定过程中,较长时间无操作,则自动恢复为正常显示方式(选做)。
  (6)设计合理的协议,实现下位机与上位机的通信:下位机定时传输数据、超限报警时发送紧急信息、上位机随时要求下位机传输数据等操作。上位机可以用串口调试工具直接发送数据和接收数据。上位机也可以用相应软件设计数据接收与发送界面(选做)。

3硬件设计

3.1硬件方案选择

  本次课程设计基于实验室提供的实验板开发,硬件部分采用了统一的方案。具体方案包括使用89S51处理芯片和8255A(U3)接口芯片,将数据显示在八位数码管上。PA端口用于控制数码管的字段码输出,PB端口用于控制字位码输出,PC端口用于控制矩阵键盘的电平检测。此外,单片机的P3.2引脚外接有源蜂鸣器,用于实现超限报警和按键提示音功能。实验板如下图所示

图3-1-1 硬件实验板图

  它是一种可编程通用并行接口芯片,它有24条可编程的I/0引脚,采用40脚双列直插式封装,单一+5V电源,全部输入/输出均与TTL电平兼容。在8255A中有A、B、C三个并行输入/输出端口,其功能全部由程序设定,每个端口都有自己的特点。A口、B口通常作为独立的I/0端口使用,C口也可以作为一般的I/0端口使用,但当A口、B口作为应答式的I/O端口使用时,C口分别以来为A口、B口提供应答控制信号。采用8255A作为计时时钟的输入/输出接口,8255A的三个端口设置如下:A口工作与方式0,作为输出口,驱动显示字段码,B口工作与方式0,作为输出口,驱动显示字位码,作为位选线;C口输入控制。

3.2主要芯片端口分配

(1)AT89S51的资源分配

端口 配置说明
P0 数据总线和地址总线
P1 L0~L7(LED灯)
P2 P2.0(8255-U3片选端)
P3 P3.2有源蜂鸣器
其他 电源端口、片选端口、接地、晶振、读写端口

(2)8255-U3的资源分配

端口 配置说明
PA 输出数码管八个“字段码”
PB 输出数码管八个“字位码”
PC 矩阵按键

3.2硬件资源具体分配

名称 作用
数码管 时钟、日期与温度的数据显示
K0 数字7/年份加1/报警参数加1
K1 数字8/月份加1/报警参数减1
K2 数字9/天数加1
K3 定时滚动显示模式
K4 数字4/年份减1
K5 数字5/月份减1
K6 数字6/天数减1
K8 数字1
K9 数字2
K10 数字3
K13 数字0
K11 设置温度报警参数
K12 进入设置时间状态
K14 进入设置时间状态
K15 退出设置状态,正常显示状态下切换时间/年月日显示
L0 自检完成指示灯
L5 时间设置状态指示灯
L6 日期设置状态指示灯
L7 温度超限警报指示灯

3.3电路原理图

图3-3-1 最小系统板原理图
图3-3-2 实验板仿真原理图

3.4部分硬件电路说明

3.4.1 数码管显示模块及方案选择

  静态驱动:数码管公共端接地,每一位数码管的八个段都有八个端口来驱动显示,编程方式简单,而且数码管的显示亮度高,但占用端口多。硬件电路复杂。

  动态驱动:数码关公共端由一个端口控制来选择要显示的位,把数码管的各位的八个段对应并联由一个端口来驱动显示。占用IO端口少,编程繁琐。硬件电路简单。

  方案选择:由于实验板IO端口数有限,为了节省端口,利于系统硬件的资源分配,故数码管显示用动态驱动方式。8255芯片用来扩展端口,将单片机的P0端口与8255的D7~D0三态双向数据线相连,以此来控制8255的PA、PB和PC端口。74HC240是双线八路反相缓冲器/线路驱动器,具有三态输出。该三态输出由输出使能端1OE和2OE控制。任意nOE上的高电平将使输出端呈现高阻态。在本电路中,PA端口通过两个74HC240三态缓冲器与数码管的显示位相连。而PB端口则通过两个74HC240与数码管的段码位相连。

图3-4-1 数码管电路

3.4.2矩阵键盘模块

  矩阵键盘本质是使用8个io口来进行16个按键的控制读取,可以减小io口的使用,用4条I/O线作为行线,4条I/O线作为列线组成的键盘。行线和列线是矩阵键盘模块中用于连接按键和控制器的导线。它们以交叉方式排列,形成了一个行和列的矩阵结构。行线通常连接到按键的一个触点上,而列线则连接到另一个触点上。在行线和列线的每个交叉点上,设置一个按键。而这样的按键中按键的个数是4 X 4个。

图3-4-2 4x4矩阵键盘

3.4.3 ADC0809模数转换模块

  ADC0809是带有8位A/D转换器、8路多路开关以及微处理机兼容的控制逻辑的CMOS组件。它是逐次逼近式A/D转换器,可以和单片机直接接口。存在一个8路模拟开关、一个地址锁存与译码器、一个A/D转换器和一个三态输出锁存器组成。多路开关可选通8个模拟通道,允许8路模拟量分时输入,共用 A/D转换器进行转换。三态输出锁器用于锁存 A/D 转换完的数字量,当OE端为高电平时,才可以从三态输出锁存器取走转换完的数据。ALE 为地址锁存允许输入线,高电平有效。当 ALE 线为高电平时,地址锁存与译码器将A,B,C三条地址线的地址信号进行锁存,经译码后被选中的通道的模拟量进入转换器进行转换。A,B和C为地址输入线,用于选通 IN0-IN7 上的一路模拟量输入。本电路仅连接IN0与IN1。

图3-4-3 ADC0809

4软件设计

  数据采集终端的控制程序,根据作用划分为自检和总初始化,定时器中断服务子程序,控制程序主体四大部分;其中控制程序分为界面显示部分,操作键盘部分,温度检测部分,串口通信部分。

4.1设计思路

  首先编写开机自检程序。在系统上电后,检查相关接口及外设:数码管显示器、指示灯和蜂鸣器是否正常工作并向上位机发送通知,表示单片机自检完毕。然后先将时钟显示部分代码编写完成,再编写年月日显示部分代码,注意闰年与每一个月份的判断,再将其整合成正常显示部分。接下来处理温度采集。调用AD0()和AD1()函数分别进行数据的采集。通过这些函数读取温度传感器所连接的模拟输入端口,并将温度数据转换为数字值。编写一个与定时器0相关的标志位,选择四者者其一在正常显示时进行轮流显示。接着编写设置时间时闪烁的子程序,因为要进行检错所以不能将数据直接存至显示的存储单元,因此还需要设置暂存单元,以及选择位数的单元,同时编写矩阵按键的功能,判断每个摁键摁下的框架写完之后再往里面添加每个按键摁下时要执行的功能。定时器0用于正常显示时的时间计时,定时器1用于串口通信。

4.1.1总框图流程说明

图4-1-1 程序总流程图

4.1.2主工作流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void main()
{
Delay(60); //等待各芯片退出复位状态
IO_Init(); //调用--- I/O初始化 ---子程序
test(); //调用--- 开机自检程序 ---子程序
Timer_Init(); //调用--- 定时器初始化 ---子程序
sendstring("hello!\r\n"); //通知上位机单片机自检完毕
while(1) //进入循环
{
AD0(); //调用--- 采集ad0数据 ---子程序
AD1(); //调用--- 采集ad1数据 ---子程序
Show_control(); //调用--- 显示模式切换 ---子程序
Disp_8bit(); //调用--- 数码管亮灯 ---子程序
mode_switch_time(); //调用--- 定时切换时间 ---子程序
Time_time(); //调用--- 更新时间日期 ---子程序
beez_time();
Da_conversion();
V_key_scan(); //矩阵键盘扫描、滤波
V_key_function(); //矩阵键盘键功能处理
sendzip(); //调用--- 传输采集数据 ---子程序
}
}

4.2局部程序设计说明

4.2.1总初始化和自检

图4-2-1 自检程序流程图
  方案:
  通过延时驱动L0L7闪烁,八位数码管八段全亮,驱动蜂鸣器鸣叫0.5S。对U3进行设置,配置端口工作方式,将A口设置为输出(用于驱动数码管字段),B口设置为输出(用于驱动数码管字位),C口设置为输入(用于键盘行列线)。对U3的A口写入字段码,对U3的B口写入字位码,驱动数码管的字位码八位全点亮。对P1口输入0x00,驱动L0L7点亮。将P3.2置为0,驱动蜂鸣器鸣叫,并延时1秒后将其置为1。设置定时器的工作方式,并开启定时器中断使能。按顺序对芯片进行配置。最后,程序进入一个无限循环,执行正常工作逻辑。

4.2.2定时器中断服务子程序

图4-2-2 定时器0中断服务流程图

(1)时间/日期更新程序

图4-2-3 时间/日期更新程序流程图
  方案:
  根据定时器的工作模式和配置,计算每次产生定时中断所经过的时间。利用计数的方式来确定时钟的走时。引入一个基础计数变量count,用于计算中断产生的次数。该计数变量会在每次定时器中断发生时进行加一操作,并根据设定的初值判断是否满一秒。当满一秒时,清零该计数变量并使后一级的秒变量加一,从而更新时钟的时、分、秒、年、月、日等时间信息。
  闰年判断:
  ①能直接被4整除且不能被100整除的是闰年;
  ②能直接被400整除的是闰年。

4.2.3控制程序主体

4.2.3.1界面显示部分

  (1)拆字功能
  方案:
  分别为显示日期、显示时间和显示温度功能写了三个拆字模块的函数,通过显示标识位判断在主流程判断调用哪个拆字子函数。对于日期显示,我在函数中进行查表,并添加0到9的数据查询。在存储数字之前,将相应的显示单元的数据加上18,以指向带小数点的显示字符。这样可以实现日期的20XX.XX.XX格式显示。类似地,我为时间显示编写另一个函数来实现拆字功能。在该函数中,首先存储”-“字符在表格中的数据,并进行一次移位和移数据操作。然后,按照正常的拆字方式将时间的高低四位存储到相应的显示单元中。这样可以实现带有”-“符号的时间显示。温度显示部分同上。
  (2)定时切换显示子程序

图4-2-4 动态显示切换流程图

  方案:
  首先预设一个标识位用于年月日、时间和温度界面显示的切换,根据定时器中断触发,修改标识位的数据来实现显示的切换。并且可以根据需要设置不同的时间间隔本文程序采用每隔5s切换一次。
  (3)闪烁功能实现
  方案:
  使用定时器0配置为方式1,即16位工作模式。在中断服务子程序中,根据需要的闪烁时间间隔,修改闪烁标志位的状态。在设置时间、日期和温度时根据读取到的位数,将指向的位数对应的显示数组里面的数据,与空格数据互相交替,并经过定时器0的固定时间,造成视觉上闪烁的观感。
  (4)输入检错功能

图4-2-5 输入检错流程图

  方案:
  设置时间时,当输入的数据不符合规范时,则判定为无效操作。例如在输入26小时的时候,即使摁下6也无法对其个位赋值。只有在十位为1或0时,摁下6号键才是有效的;设置日期时,若原始数值为2024年2月29日,此时增加年份为2025年,则会调用日期检错函数,使其自动变为2025年2月28日,并无法将其增加至29日,即校准了日期。

4.2.3.2键盘操作部分

  (1)按键消抖
  方案:
  使用滚动存储的方式而非采用延时消抖的方法,避免了对CPU资源的浪费,以及导致显示时候的窜显。预设几个存储单元与两个关键的旧态新态单元,利用主流程的时间消耗,当之前的几个存储单元逐个赋值至全部相等后,代表按键的机械抖动已经消除,,此时再将当前按键状态存入新态存储单元,与按键旧态单元即可形成键值电平的判断,对按键摁下动作进行选择。
  (2)键盘扫描子程序
  方案:
  为了实现只有在按键摁下的时候才能执行相应的功能,因此需要模拟它的电平变化。按键的摁下实际上是一个下降沿的状态,从没有摁下的高电平转为被摁下后的低电平,因此先判断滚存单元旧态是否是没被摁下的电平状态,再判断该按键是否是被摁下后的电平状态,逐个执行下来就能确定是否有按键进行了被摁下的动作。

4.2.3.3温度检测部分

  (1)温度采集子程序
  方案:
  使用可调电位器来模拟温度输入。通过调节电位器的旋钮来改变电压值,模拟不同的温度值。确保可调电位器的范围能够覆盖目标温度范围,在本方案中为-20℃至65℃。先由模数转换芯片ADC0809将模拟量转换成0-255的数字量再通过计算将其范围限定在-20~65,通过控制数码管显示该值。
数字量和温度对应关系如下:

A0:被测参数起点
Am:被测参数最大值
Dm:数字量最大值
Dx:实测数字量
  本考虑采用中值滤波的数据滤波方式提高系统的稳定性和准确性,但最后实现效果并不理想,故放弃。
  (2)设定温度报警阈值

图4-2-6 设置温度阈值流程图

  方案:
  预设一个存储变量(初始值为上限35℃),作为阈值与两个温度通道采集到的数值比较的单元变量,在设置温度报警参数界面将上限参数存入这个变量,保存数据并返回正常显示界面后温度采集子程序不断对是否超出范围是否进行判断,超出后置零蜂鸣器和LED灯进行报警。
  (3)声光报警功能的实现
方案:

图4-2-7 声光报警功能流程图

  通过定时器中断来驱动整个流程。预设一个beez_flag_time变量,在每次中断触发时,beez_flag_time自加1。当超过200时置零。因此可以使用beez_flag_time变量来控制蜂鸣器和LED灯的开关状态,并通过判断beez_flag_time是否超过50来确定何时开启和关闭它们。当温度超出阈值时,led灯将以0.5s的间隔闪烁,同时蜂鸣器也以此频率鸣叫报警。

4.2.4串口通信

  方案:
  printf函数使用putchar函数构建一个字符串并写入输出流。fmtstr是一个格式参数,可以由字符,转义序列和格式字符串组成。printf函数在格式化输出时,向下调用了char putchar(char c);这个函数,在“stdio.h”里可以发现有这个函数,所以我们需要自己构造一个这样的函数,即通过串口putchar()。
  值得注意的是keil C51中使用printf打印uchar类形的整数的时候,正确的打印控制符是:%bx,%bu。编写一个发送函数,用于将字符串通过串口发送出去。定义一个名为sendbyte()的函数。在函数内部,使用循环逐个字符地发送字符串中的每个字符,直到遇到字符串结束符\0为止。发送字符的方法可以是通过写入UART数据寄存器来实现。

5系统功能与操作说明

  系统启动时进入自检,然后进入时钟模式,过5s轮流显示年月日、AD0温度和AD1温度,摁下K7键可以立刻切换,摁K12进入时钟修改界面,K0K10与K13对应选择可修改数据的赋值。摁K14进入日期修改界面。K0K6对应选择修改年、月、日三位数据。摁#退出修改模式并保存相应设置。系统运行过程中温度超出限值时蜂鸣器发出响声、指示灯闪烁。可在串口助手中查看收集到的温度数据。
5.1键盘操作界面

K0 K1 K2 K3
滚动模式 滚动模式 滚动模式 滚动模式
K4 K5 K6 K7
固定模式 固定模式 固定模式 固定模式
K8 K9 K10 K11
报警参数 报警参数 报警参数 报警参数
K12 K13 K14 K15
设置时间 设置日期 设置时间 设置日期

图5-1-1 主键盘按键定义

图5-1-2 日期设置模式下的按键定义

图5-1-3 时间设置模式下的按键定义

图5-1-4 设置温度报警参数模式下的按键定义
5.2数码管显示界面及显示格式说明

图5-2-1 数码管显示界面

  (1)时间显示:12-30-02 12时-30分-02秒
  (2)日期显示:2024.2.25  2024年02月25日
  (3)温度显示:A0 35.2℃ 通道0温度检测为35.2摄氏度
  (4)温度显示:A1 -5.6℃ 通道1温度检测为-5.6摄氏度

5.3LED显示说明

  (1)L0:开机自检完成后常量
  (2)L5:进入时间设置模式时常量,退出时关闭
  (3)L6:进入日期设置模式时常量,退出时关闭
  (4)L7:温度超限报警

5.4操作说明

  (1)时钟调校:开机完成自检后,按下K12进入时钟调校界面,数码管闪烁的数字为可调整部分。通过输入数字键可以修改当前时钟的时、分、秒。按下确定键则保存当前修改设置后返回基本界面,若所设时间超值,则判定为无效操作。长时间无操作则会自动返回显示模块。本文为20s。
  (2)日期设置:开机完成自检后,按下K14进入时钟调校界面,按下K0K3可以分别增加年、月、日数值;按下K4K6可以减少年、月、日数值。按下确定键则保存当前修改设置后返回基本界面。
  (3)温度采集和处理:控制器系统会定时采集温度数据,并可以在显示界面中显示实际温度值。
  (4)超限报警:本系统具有温度报警功能,用于监测温度是否超出设定范围。调整电位器0或电位器1使其数值超过上下限时,蜂鸣器会发出警报声,指示灯会亮起,同时数码管会显示相应通道的报警信息。并且上位机会接收到“ERROR!—ADX”警报字样。调整回正常温度时退出报警模式。
  (5)数据记录:单片机会定时将温度和时间数据发送给上位机。上位机可以使用串口调试工具或相应软件接收并处理来自控制器系统的温度和时间数据。

图5-4-1 上位机接收系统采集的温度数据与警报

6调试记录

  1、对各个端口进行总初始化,并编写开机自检程序。以流水灯模式检测数码管显示器、指示灯是否正常。同时,开启蜂鸣器。
  2、分别编写正常模式下的时钟与日期的显示模式,时钟添加“—”符号,日期添加“.”,同时网上查询年月日计算日期的公式,完成日期对闰年以及每个月份对应天数的判断。
  3、增加数据检错部分,在修改其他数据时候对整体数据进行判断,若不符规则就强制修正。在编写完日期代码后先加快增加速度每0.5s天数加一观察2月份以及其它月份天数的增加是否正常,无误后增加标志位判断显示那种模式的数据
  4、添加滚动显示模式,在中断程序中新增变量,并在1000(即5秒)范围内自增,定时改变标志位判断显示那种模式的数据从而达到数码管以一定的时间间隔交替显示时间日期的效果。
  5、编写采集温度数据程序。根据公式将电压值转换成-20~65℃。并自定义温度的上下限,当超出范围后调用L0与蜂鸣器进行警告。由于蜂鸣器常鸣影响数码管显示的稳定性,因此再次在中断函数里新增变量使其隔0.5s间断警报。然后对显示模式的变量持续清空,使温度超限后数码管固定显示在温度模式,不再滚动显示直到调整至正常值。
  6、添加矩阵按键功能,通过按键选择修改日期与时间。
优化键盘,将设置时间的部分修改为数字键盘。
  7、根据题目要求对代码进行完善,例如完成一次时间修改后就无法再次进入时间设置模式,AD0超限报警时声音过小等等小问题,使代码更加的合理。

7课程设计总结

  经过了两个星期的课程设计,我受益颇丰,它帮助我巩固了对之前c语言的学习与理解,网上资料的查询也让我提高了自己动手的能力。相较于之前的实验课来说,课程设计的难度相当于拔高了好几个档次,但它带给我的好处却是诸多的,之前在学习单片机的时候,一次代码量一般都不超过一百行,真正逻辑处理的部分更是少之又少。而这次的课程设计却让我学会了整体的统筹规划。
  学习该门课程知识时,其思维方法也和其它课程不同,该课程偏重于工程思维,具体地说,在了解了微处理器各种芯片的功能和外部特性以后,剩下的是如何将它们用于实际系统中,其创造性劳动在于如何用计算机的有关技术和各种芯片,设计实用的电路和系统,再配上相应的应用程序,完成各种实际应用项目。
  这次的实验感觉挺难的,主要的困难来自对程序的理解。功夫不负有心人,经过自己的不懈努力,最后对实验的原理有了清晰的认识。虽然无法从上位机传输数据指令操作,但是就系统功能来说,我觉得还是做的可以的。
  这次课设却让我们对实验板有了足够的了解,让我们知道了实验板上各个模块的用法;而且它还让我们对自己动手写程序来控制实验台的运作有了一定的基础。虽然实验板只是一个小型的模拟平台,但是通过对它的学习和操作,我们对有关接口的知识将会有一个更广泛的认识,而且它对我们以后的学习也会有帮助的。
  总之,这次课程设计对于我有很大的帮助,通过课程设计,我更加深入地理解了,微机原理课程上讲到的各种芯片的功能,以及引脚的作用,同时加深了对于主要芯片的应用的认识,同时在实验室的环境里熟悉了程序的编写过程和运行过程,最后还提高了自己的动手能力,真的很感谢老师们的悉心指导。