您的当前位置:首页正文

桂林电子科技大学信息科技学院嵌入式实训下

来源:华佗小知识


《嵌入式系统开发与应用实训》实训报告

倒计时秒表

1 整机设计

1.1 设计要求

使用Qt编程,在ARM实验箱的液晶显示屏幕上实现99秒倒计时,采用AT89S51单片机模块与ARM9实验箱之间的串口通信,实现数码管显示、按键控制的同步,通过按键可以实现“运行/暂停”、“调整计时初值”的功能,当倒计时到0时,会有指示灯闪烁或亮。使用串口连接单片机模块与ARM9实验箱,单片机模块要求:接收串口发来的命令进行输出显示,当按键按下后将按键信息通过串口发送出去;ARM9实验箱模块要求:通过Qt编程实现相应的计算和控制功能。即单片机要求承担信息输入、输出的“中转站”功能,不承担主控任务。

1.1.1设计任务

采用AT89S51单片机与ARM9实验箱之间的串口通行,通过Qt编程设计一个99秒倒计时秒表。

1.1.2性能指标要求

1、使用Qt编程,在ARM实验箱的液晶屏幕上实现99秒倒计时;

2、实验箱通过串口与单片机模块通信,实现数码管显示、按键控制的同步;

3、通过按键实现“运行/暂停”、“调整计时初值”功能;

4、倒计时为0时,指示灯闪烁;

5、扩展多位数码管,实现多位显示(动态扫描);

2方案设计

2.1方案论证

方案一:做个简单的普通倒计时秒表。就是能让它倒计时,还可以同按键控制它的开始与暂停,能够实现单片机与实验箱之间的串口通信。

方案二:做个多功能倒计时秒表,通过按键可以实现“运行/暂停”、“调整计时初值”功能,让单片机承担主控任务,ARM实验箱上做的UI界面仅仅承担同步显示功能。

方案三:做个多功能倒计时秒表,通过按键可以实现“运行/暂停”、“调整计时初值”功能,单片机可以接收串口发来的命令进行输出显示,当按键按下后将按键信息通过串口发送出去,ARM实验箱可以实现与单片机的同步,同时可以进行互相控制,即通过ARM实验箱可以控制单片机显示和ARM实验箱上的UI的同步显示,繁反之通过单片机也可以控制实验箱与单片机的同步操作功能。显示采用多位数码管来实现。

经过以上对方案的说明:方案一过于简单,无法实现本次实训的功能要求;方案二叫方案一有改进,但是无法实现互相控制的功能要求,也就是失去了本次实训的意思(本次实训主要是ARM上的Qt编程);本次实训采用了方案三。

2.2工作原理

AT89S51单片机支持串口通信,串口有4个模式。可分别用串并转换、并串转换、异步串行通信(2中模式)。异步串行通信中,有1+8+1和1+8+1+1两种帧格式,多机通信是特殊的通信方式。基本原理是两组移位寄存器,将并行通信转换成串行通信模式(发送部分),或反之(接收部分)。可全双工运行。速度通过移位脉冲决定,具体一般通过定时器1的自动壮哉模式产生的溢出脉冲给出。以上是物理层和数据链路层的单片机串口模式的约定,其他层需要软件人员根据需要自行把握。另外。电平需要根据实际通信环境做改变,如232、485或红外等。

SCS2410 UART单元提供2个独立的异步串行通信口。皆可共组于中断和DMA模式,每个单元UART单元包含一个16字节的FIF0,用于数据接收和发送,SCS2410 UART包括可编程波特率、红外发送/接收、1/2个停止位、5位/5位/7位/8位数据宽度和奇偶校验。

虚拟机可以在串口模式下试下与SCS2410 UART的通信,SCS2410 显示终端2实现程序的功能后,可以通过串口与与51单片机实现串口通信。通过对两芯片的一些专用寄存器的应用,就可以实现两机之间的彼此通信。

2.3总体框图

倒计时秒表设计总体框图

2.4各功能电路实现原理及电路设计

1)单片机最小系统:保证单片机的正常工作,一般包括:单片机、晶振电路、复位电路。见左下图。

单片机最小系统 下载口

2)下载口:单片机的程序下载接口,主要接在单片机的P1口还有就是复位接口、电源和地(GND)。见右上图

3)报警指示电路:报警指示电路由二极管、三极管、蜂鸣器和两电阻组成,倒计时到0的状态下,禁止倒计时,二极管闪烁,发出报警声。见右下图

报警指示电路 按键电路

4)按键电路:由四个按键、四个电阻组成分别实现秒表暂停/运行、加计时、减计时、复位功能。见左上图。

5)数码管显示电路:采用的是共阴数码管,通过动态扫描实现秒表数字的显示。见右下图

数码管显示电路 串口连接电路

6)串口连接电路:采用的是MAX232电压转换芯片,通过电压转换芯片连接串口,实现单片机与arm间的串口通信。见左上图

3 软件设计

3.1 UI截面图

#include \"widget.h\"

#include \"ui_widget.h\"

Widget::Widget(QWidget *parent) :

QWidget(parent),

ui(new Ui::Widget)

{

ui->setupUi(this);

ui->lcdNumber->setSmallDecimalPoint(true);

sec=43.21;

ui->lcdNumber->display(sec);

SEC = 60;

ui->spinBox->setValue(SEC);

s1 = new QTimer;

connect(s1,SIGNAL(timeout()),this,SLOT(display()));

connect(ui->pushButton_3,SIGNAL(clicked()),this,SLOT(run_stop()));

connect(ui->pushButton_4,SIGNAL(clicked()),this,SLOT(reset()));

connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(add()));

connect(ui->pushButton_2,SIGNAL(clicked()),this,SLOT(sub()));

s2 = new QTimer;

s2->start(100);

connect(s2,SIGNAL(timeout()),this,SLOT(readCom()));

myCom = new Posix_QextSerialPort(\"/dev/tts/0\

myCom ->open(QIODevice::ReadWrite);

//以读写方式打开串口

myCom->setBaudRate(BAUD9600);

//波特率设置,我们设置为9600

myCom->setDataBits(DATA_8);

//数据位设置,我们设置为8位数据位

myCom->setParity(PAR_NONE);

//奇偶校验设置,我们设置为无校验

myCom->setStopBits(STOP_1);

//停止位设置,我们设置为1位停止位

myCom->setFlowControl(FLOW_OFF);

//数据流控制设置,我们设置为无数据流控制

myCom->setTimeout(50);

}

Widget::~Widget()

{

delete ui;

}

void Widget::display()

{

sec = sec - 0.01;

if(sec<0)

{

run_stop();//stop

ui->lcdNumber->display(0);

update();

send(sec,1,0);

}

else

{

send(sec,0,0);

ui->lcdNumber->display(sec);

}

}

void Widget::run_stop()

{

QString str = ui->pushButton_3->text();

if(str == \"Start\")

{

s1->start(10);

ui->pushButton_3->setText(\"Stop\");

}

else

{

s1->stop();

ui->pushButton_3->setText(\"Start\");

}

}

void Widget::reset()

{

SEC = ui->spinBox->value();

ui->lcdNumber->display(sec = SEC);

send(sec,0,1);

update();

}

void Widget::paintEvent(QPaintEvent *)

{

QPainter painter(this);

painter.setPen(Qt::gray);

if (sec < 0)

painter.setBrush(Qt::red);

else

painter.setBrush(Qt::white);

painter.drawEllipse(300,50,25,25);

}

void Widget::readCom()

{

QByteArray temp = myCom->readAll();

switch(temp[0])

{

case 0x01:run_stop();break;

case 0x02:add();break;

case 0x03:sub();break;

case 0x04:reset();break;

default:break;

}

}

void Widget::add()

{

if(SEC == 99.0)

return;

else

ui->spinBox->setValue(++SEC);

}

void Widget::sub()

{

if(SEC == 0.0)

return;

else

ui->spinBox->setValue(--SEC);

}

void Widget::send(double p,int ledd,int spk)

{

char str[4];

str[0] = 0xBB;

str[2] = (int)m + 1 * 128;

str[1] = (int)((m - (int)m)*100) + 1 * 128;

str[3] = 0;

myCom->write(str);

}

4 制作与调试过程

首先在收集资料的基础上画好原理图,自己编写单片机程序,然后用proteus仿真软件验证功能的正确性。在仿真实现的情况下,做出硬件电路板,首先通过下载接口将硬件电路与电脑连接,这个下载接口不仅仅可以下载程序还可以给芯片供电,接好下载线后,测试芯片是否可以正常工作,在芯片和各个模板电路能正常工作的情况下,将之前写好的程序下载到硬件电路上。之后就开始用Qt编写ARM的程序,花了两天的时间终于编写好了ARM的c++程序,在编译通过之后。就开始在虚拟机中运行测试,之后到实验室将虚拟机与ARM实验箱通过串口连接起来。在ARM实验箱的显示屏上验证倒计时秒表功能与实训要求是否相符合,即将Qt写好的程序先拷贝到虚拟机下运行,再通过Qt的嵌入式开发工具链编译链接生成实验箱可以执行的文件,将这个可执行文件拷贝到实验箱与虚拟机共享目录下运行,在实验箱上观察秒表倒计时显示是否与题目要求0~99倒计时相符合,同时验证报警指示功能是否与实训要求相符合,接着就是测试四个功能的作用是否是题目要求相匹配,我首先按下暂停/运行按键,观察秒表到时候是否可以正常运行,再在暂停状态下按下秒表复位,验证秒表是否可以实现复位功能,在接着在此状态下验证加计时和减计时的功能是否可以实现。接着拔掉电脑的串口线,通过串口线连接单片机与实验箱,验证各个按键功能和显示显示是否可以同步,同时是否可以互相控制。我在硬件电路完美实现的情况下,按照的上面的调试过程去做,结果是没有遇到什么不正常的问题,我的硬件做出来就可以正常工作了。

4 电路测试

硬件电路完成之后验证基本功能,即对数码管显示功能的测试,通过编写一个简单的小程序给数码管相应的I/O赋值,观察数码管是否可以正常;接着就是验证按键是否可以正常使用,在验证数码管小程序的基础之上加入按键功能,对按键I/O进行修改这样完成

了对四个按键的测试;蜂鸣器和指示灯的测试就是对相应I/O赋值观蜂鸣器是否可以发出声音和指示灯是否可以正常显示。串口的测试就是编写单片机和ARM小程序,进行简单的通信观察彼此是否可以收发字符串。正确测试电路这些基本功能之后就可以进行试训程序的编写了。

4.1 指标测试

1、0~99秒倒计时的正常显示;

2、报警声音和指示灯在倒计时结束时能按规定运行;

3、四个按键分别可以实现秒表的暂停/运行,复位,加计时,减计时;

4、可以扩展其他功能(数码管的多位显示,报警功能)

4.2 误差分析

实训过程中对于电路测试中出现了一些误差,首先出现的就是数码管的显示,通过对数码管引脚图的分析,最后成功解决;还有就是功能按键不起作用,通过对按键引脚电平的从测试(在按下前后状态下),最后也成功解决此误差;还有就是程序误差,实验箱与单片机之间不能实现同步控制,最后通过对程序的修改也成功解决。

附 录

1、 电路原理图

2、 PCB图

3、 UI截面图

4、 片机程序

#include

#define uchar unsigned char

#define uint unsigned int

unsigned char cnt; // 区分数码管显示位

unsigned char KEY = 0; // 按键锁定

unsigned char speak = 1; //蜂鸣器 不响

unsigned char led = 0; //指示灯 不亮

int mg=43,ms=21; //数码管整数位(0~99)小数位(0~99) 初始化显示数字

unsigned char tab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; 数码管0-9断码表

void uart_isr() interrupt 4 //中断方式4,串行口I/O中断

{

/*******************************************

接收模块

0xBB 表示接下来要接收两个数码管数据

单片机串行口数据缓冲器SBUF

*******************************************/

if(RI) //接收中断标志位RI

//

{

RI = 0;

if(SBUF == 0xBB)

{

while(!RI);

RI=0;

ms=SBUF;

ms = SBUF & 0x7f;

led = SBUF/128;

while(!RI);

RI=0;

mg=SBUF;

mg = SBUF & 0x7f;

speak = !(SBUF/128);

}

}

}

void Com_Init(void) //计数器初始化

{

TMOD = 0x20;//T1计时器

PCON = 0x00;//波特率不倍增,在方式1、SCON = 0x50;// 串行口控制器配置

TH1 = 0xFD; //T1高8位

TL1 = 0xFD;//T1地8位

2、3中0表示不倍增,1表示倍增

TR1 = 1;

ES=1;

}

void Timer_Init(void) //配置定时器

{

TMOD|=0x01;

TH0=0xFC;

TL0=0x18;

TR0=1;

EA=1;ET0=1;

}

void Show_Init() //按键、蜂鸣器初始状态

{

P2_0=1;

P2_1=1;

P2_2=1;

P2_3=1;

P1_2=1;

}

void delay(void) //延时

{

unsigned char a,b;

for(b=249;b>0;b--)

for(a=17;a>0;a--);

}

void timer() interrupt 1 using 0 //中断方式1

{

TH0=0xFC;

TL0=0x18;

switch(cnt%4) //数码管动态扫描

{

case 0:P2_4=0;P2_5=1;P2_6=1;P2_7=1;P0=tab[mg/10];break;

case 1:P2_4=1;P2_5=0;P2_6=1;P2_7=1;P0=tab[mg%10]+128;break;

case 2:P2_4=1;P2_5=1;P2_6=0;P2_7=1;P0=tab[ms/10];break;

case 3:P2_4=1;P2_5=1;P2_6=1;P2_7=0;P0=tab[ms%10];break;

}

P3_7 = speak; //定义蜂鸣器接口

P1_2 = led; //定义led指示灯接口

cnt++;

}

void send(unsigned char c)

{

SBUF = c; //发送中断标志位TI

while(!TI);

TI = 0;

}

void main()

{

Com_Init();

Timer_Init();

Show_Init();

while(1)

{

/********************************************

发送模块

暂停/启动:启动停止按键

加:整数位上限加一

减:整数位上限减一

复位:清除当前数字 恢复

********************************************/

if(!KEY){

if(!P2_0) //暂停/启动

{

delay();

if(!P2_0)

{

send(0x01);

KEY=1;

}

}

if(!P2_1) //加计数按键

{

delay();

if(!P2_1)

{

send(0x02);

KEY=1;

}

}

if(!P2_2)////减计数按键

{

delay();

if(!P2_2)

{

send(0x03);

KEY=1;

}

}

if(!P2_3) //复位按键

{

delay();

if(!P2_3)

{

send(0x04);

KEY=1;

}

}}

if(P2_0 && P2_1 && P2_2 && P2_3) //锁定按键 使其只能按一次发一次

{

delay();

if(P2_0 && P2_1 && P2_2 && P2_3)

{

KEY=0;

}

}

}

}

5、 Qt的C++程序

#include \"widget.h\"

#include \"ui_widget.h\"

Widget::Widget(QWidget *parent) :

QWidget(parent),

ui(new Ui::Widget)

{

ui->setupUi(this);

ui->lcdNumber->setSmallDecimalPoint(true);

sec=43.21;

ui->lcdNumber->display(sec);

SEC = 60;

ui->spinBox->setValue(SEC);

s1 = new QTimer;

connect(s1,SIGNAL(timeout()),this,SLOT(display()));

connect(ui->pushButton_3,SIGNAL(clicked()),this,SLOT(run_stop()));

connect(ui->pushButton_4,SIGNAL(clicked()),this,SLOT(reset()));

connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(add()));

connect(ui->pushButton_2,SIGNAL(clicked()),this,SLOT(sub()));

s2 = new QTimer;

s2->start(100);

connect(s2,SIGNAL(timeout()),this,SLOT(readCom()));

myCom = new Posix_QextSerialPort(\"/dev/tts/0\

myCom ->open(QIODevice::ReadWrite);

//以读写方式打开串口

myCom->setBaudRate(BAUD9600);

//波特率设置,我们设置为9600

myCom->setDataBits(DATA_8);

//数据位设置,我们设置为8位数据位

myCom->setParity(PAR_NONE);

//奇偶校验设置,我们设置为无校验

myCom->setStopBits(STOP_1);

//停止位设置,我们设置为1位停止位

myCom->setFlowControl(FLOW_OFF);

//数据流控制设置,我们设置为无数据流控制

myCom->setTimeout(50);

}

Widget::~Widget()

{

delete ui;

}

void Widget::display()

{

sec = sec - 0.01;

if(sec<0)

{

run_stop();//stop

ui->lcdNumber->display(0);

update();

send(sec,1,0);

}

else

{

send(sec,0,0);

ui->lcdNumber->display(sec);

}

}

void Widget::run_stop()

{

QString str = ui->pushButton_3->text();

if(str == \"Start\")

{

s1->start(10);

ui->pushButton_3->setText(\"Stop\");

}

else

{

s1->stop();

ui->pushButton_3->setText(\"Start\");

}

}

void Widget::reset()

{

SEC = ui->spinBox->value();

ui->lcdNumber->display(sec = SEC);

send(sec,0,1);

update();

}

void Widget::paintEvent(QPaintEvent *)

{

QPainter painter(this);

painter.setPen(Qt::gray);

if (sec < 0)

painter.setBrush(Qt::red);

else

painter.setBrush(Qt::white);

painter.drawEllipse(300,50,25,25);

}

void Widget::readCom()

{

QByteArray temp = myCom->readAll();

switch(temp[0])

{

case 0x01:run_stop();break;

case 0x02:add();break;

case 0x03:sub();break;

case 0x04:reset();break;

default:break;

}

}

void Widget::add()

{

if(SEC == 99.0)

return;

else

ui->spinBox->setValue(++SEC);

}

void Widget::sub()

{

if(SEC == 0.0)

return;

else

ui->spinBox->setValue(--SEC);

}

void Widget::send(double p,int ledd,int spk)

{

char str[4];

str[0] = 0xBB;

str[2] = (int)m + 1 * 128;

str[1] = (int)((m - (int)m)*100) + 1 * 128;

str[3] = 0;

myCom->write(str);

}

因篇幅问题不能全部显示,请点此查看更多更全内容