51单片机项目设计——价格猜猜猜

一、设计目的目标

1、通过PC机发送数据到STC板上

2、通过按下K2或使振动传感器受到震动开始游戏

3、通过导航按键上(下)键调大(小)数字,并显示在数码管上

4、通过按下K1确认数据

5、通过LED灯表示显示所猜数据与实际数据的大小关系

6、当猜对时蜂鸣器播放一段音乐,代表可以把该价格的物品带回家

7、在数码管最后一位显示所剩下的猜数机会,当3次都没猜对时,数码管跳零报错,按下K2可重新开始游戏

二、设计整体架构

1、分模块流程图

(1)数码管LED模块

 

(2)振动传感器

(3)无源蜂鸣器播放音乐

 

(4)导航按键

 

(5)串口通信

 

2、整体流程图设计

三、硬件原理

 

1、LED数码管

(1)电路部分

(2)LED数码管引脚定义

 

A、B、C、D、E、F、G、H分别对应LED数码管的8位段选信号,从而控制数码管显示不同的数。

(3)数码管工作原理

P0口的8位输出分别控制8个发光二极管L0~L7的阳极;而P2.3经反相器U4C控制8个发光管阴极E3;当阳极为高(对应P0口位为1)、阴极为低时,对应的二极管将会发光。

而P2.3经反相器U4C控制74HC138的使能信号E3,结合P2.0、P2.1、P2.2这3个位选控制信号确定8个LED数码管中的哪个被点亮;电阻R15~R22为限流电阻。当段选为高、使能信号有效时,对应的LED管将会发光。

通过以一定频率扫描位选信号,选择段选信号进行数码管点亮一段时间,从而给人视觉上几个数码管几乎同时显示的效果。

(3)LED灯工作原理

如图(只关注led灯部分电路),P0口的8位输出分别连接了8个发光二极管L0~L7的阳极, P2.3经过一个反相器连接到8个发光二极管L0~L7的阴极(共阴极)。根据二极管的单向导通性(当阳极为高(对应P0口位为1)、阴极为低时,二极管导通,否则不导通),若P2.3输出信号为低电平“0”,则二极管的阴极都为高电平,此时无论P0输出的是“1”还是“0”,二极管都不会导通,也就不会发光。因此想要发光二极管导通,必须先设置P2.3输出信号为“1”,再通过设置P0,点亮想要点亮的发光二极管。

(4)P0口设置与工作原理

STC系列芯片有5组8位输入口,分别为P0到P5,其中P5口仅P5.0~P5.5用于输入输出。STC芯片的所有I/O口都可以配置为四种工作模式之一:准双向口/弱上拉、推挽/强上拉、输入/高阻和开漏模式。STC15系列单片机上电复位后为准双向口/弱上拉工作模式。

每个I/O口的工作模式由2个控制寄存器中的相应位控制(PnM0和PnM1,n=0、1、2、3、4、5)。也就是说P0口的具体工作模式由P0M0和P0M1控制。具体赋值方法参照下表。

 

其他I/O口工作模式设置类似。

四种工作模式的说明:

(1)准双向口。真正的双向口指的是具有输入和输出两种模式的端口,在不同模式之间需要进行转换;如果从输入改为输出,需要对某些控制寄存器进行设定,才能完成。而51系列单片机的I/O口线在输入和输出之间没有明确的模式区别。相应端口在同样模式下,既可以作为输入,又可以作为输出。P3口除外,因为它需要连接外设。51单片机的I/O口如果要读必须先写1才可以,因此称为“准”双向口。需要大电流高电平输出能力的场合和高速场合不能使用该模式。

(2)推挽电路输入输出(push-pull)模式。推挽电路的输出端好像有两个“臂”(两组放大元件),一个“臂”的电流增加时,另一个“臂”的电流则减小,二者的状态轮流转换。对负载而言,好象是一个“臂”在推,一个“臂”在拉,共同完成电流输出任务。该电路模式的主要作用是增强驱动能力,为外部设备提供大电流,可以直接输出高电平电压。

(3)输入/高阻模式。仅用于输入。

(4)开漏电路。I/O口的开漏就是没有连接上拉电阻

2、振动传感器

(1)振动传感器电路图

 

(2)相关原理

本实验板中使用的振动传感器是一种简单的器件,管内有一跟固定的导线,在这根导线的周围有另一根较细的导线以螺旋状环绕它。可以想象为一个弹簧旁边有一跟导线。在不震动时,两根导线不会相碰,一旦振动发生,两根导线就会短接。所以我们只需判断导线是否短接了,就可以知道振动是否发生。

3、无源蜂鸣器

(1)电路原理图

 

(2)原理说明

蜂鸣器分为有源蜂鸣器和无源蜂鸣器,这里的源特指振荡源;有源蜂鸣器直接加电就可以响起,无源蜂鸣器需要我们给提供振荡源。理想的振荡源为一定频率的方波。

本stc板采用的是无源蜂鸣器,相比与有源蜂鸣器,无源蜂鸣器的优点在于价格便宜,可以通过控制其振动频率来改变发出的声音,因此,无源蜂鸣器可以用于音乐的播放。而有源蜂鸣器的优点在于使用简单,不需要编写“乐谱”。本实验板使用的无源蜂鸣器是电磁式蜂鸣器,电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。接通电源后,接收到的音频信号电流通过电磁线圈,使电磁线圈产生磁场。振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声

无源蜂鸣器只需改变Beep端口的电平,产生一个周期性的方波即可使蜂鸣器发生声音,不同的频率发出的声音不同。其中,ULN2003是一个功放,用于放大电流。电阻R14和电容C21是用来保护电路的。若人为将Beep端口的电平一直置为高电平,在没有保护电路的情况下,容易烧毁电路,但即使有保护电路也应该注意不要将Beep端口长时间置于高电平,这对器件也是有一定损害的。

而要想发出不同的乐声,我们知道每一个音符的发声频率使不同的,我们需要用计时器来精确计时,用以产生方波,这样才能发出不同的音符乐声。

4、导航按键

(1)导航按键电路及工作原理

 

导航按键在上图的标注为MINI_KEY5,导航按键的每一个方向被按下,都会引起实际电压的改变,从而可以根据这个原理,与A/D转换器配合,可以判断哪个方位被按下,获取按下后A/D转换的结果。

(2)AD数据采集电路及采集步骤说明

 

ADC数据采集的步骤:

  1. 将ADC0~7的模拟量送到比较器中,用DAC(数/模转换器)转换的模拟量与输入的模拟量通过比较器进行比较。
  2. 转换结束后,将比较结果放入转换结果寄存器(ADC_RES和ADC_RESL)。
  3. 同时,需要将ADC_FLAG软件清零。
  4. 注意硬件会自动将ADC_START清零,如果需要进行下一次转换,则需要将ADC_START置位。

特别说明:

(1)数码管所显示的ADC转换结果并不是电压值,而是电压进行转换后所得的一个值。如果需要实际的电压值可以参照STC15F2K60S2数据手册的760页上面的公式进行计算得出。

(2)ADC转换结果是一个10位数据,若ADRJ=0,则ADC_RES存放高八位,ADC_RESL存放低两位。若ADRJ=1,则ADC_RESL存放高八位,ADC_RES存放低两位。本工程采用的是ADRJ=0,而且只取了高八位结果。

数据采集对照表

操作

Seg0

Seg6-Seg7参考值(实际值)

无操作

7

31(可能值:0-31)

向右

1

06(可能值:0-31)

向下

2

12(可能值:0-31)

向里

3

17(可能值:0-31)

向左

4

22(可能值:0-31)

向上

5

25(可能值:0-31)

 

5、串口通信

(1)相关电路

 

(2)原理说明

单片机集成了USB转串口模块,对应使用RXD线接收数据,用TXD发送数据。每个串口由2个数据缓冲器(相互独立1收1发)、一个移位寄存器(一字节数据一位一位发送出去)、一个串行控制器和一个波特率发生器组成。对应发送、接收数据完成(RI、TI硬件置1)都会触发串口中断,但是无法确定是哪个触发的,所以在串口中断中我们要判断是接收数据产生的中断还是发送数据产生的中断,对于发送数据产生的中断,我们要软件将TI清0,并将数据就绪标志清0,允许下一字节数据发送,发送数据函数中通过while循环,等待发送数据准备就绪,完了将就绪的数据复制给SBUF;对于接收数据产生的中断,我们要软件将RI清0,并从SBUF中读取数据。

6、CPU引脚分配

三、软件设计与实现

1、数码管及LED灯显示模块

(1)引脚分配:

 

根据上图,分配引脚:

 

(2)初始化部分

将对应端口设置成推挽模式

 

数组duanxuan和weixuan分别控制数码管的段选信号和位选信号,flag_weixuan 和flag_duanxuan相当于两个数组的索引。例如flag_weixuan=1,flag_duanxuan=2,表示在数码管的第1位显示数字2

 

(3)显示部分:

由于E3 既是反相器输出信号也是数码管的使能信号,当 E3=0 时,LED 灯(共

阴极)亮,数码管位选信号的使能信号为 0,数码管不亮;反之,数码管亮而 LED 不亮。因此E3需要采用分时复用的方法实现。

这里初始让LED_SEL=0,选择数码管显示,当count加到10时,令LED_SEL=1,选择LED灯亮。

而具体哪个LED灯亮,通过分支语句判断所猜的数据和真实值的大小关系,对led赋不同的值,再把led复制给P0(对应于LED灯的引脚)

为了防止在拨动导航按键时出现负数等无法显示的情况,故采用保护措施

 

 

 

2、振动传感器

(1)特殊寄存器位定义

 

(2)振动传感器检测

初始化令vibrate=1,当检测到振动时,vibrate自动置为0,执行主函数中的语句。

 

3、蜂鸣器发声模块

(1)定时器初始化部分

设置定时器初值为TH0=(65535-1000)/256,TL0=(65535-1000)%256,定时1ms,即每1ms触发一次定时器中断

 

(2)定时器发声部分

每次触发定时器中断以后,进入if语句进行判断。当用户猜对数后,令flag为1,进入if语句,beep翻转,蜂鸣器发声。否则,beep=0,不发声

 

(3)音乐播放模块

music数组:根据音乐简谱编写。格式为 音符,节拍。音符为要发出的音调,节拍则是声音持续的时间。在该数组中,音符表示的格式为:十位代表是低八度,中八度还是高八度,1代表低八度,2代表中八度,3代表高八度,个位代表音符。在音符中,0xff代表休止符,表示要休止100ms,而0x00代表结束符,表示整首歌曲播放结束。

 

quzi数组:对应各个音符在定时器中的重装值,第一列是高位,第二列是低位

 

quyin函数:根据音符的曲调值找到音符在quzi数组中的基址,再加上偏移量(音符)找到music数组定义的简谱音符的重装值,并返回其在quzi数组中的位置

 

playmusic函数取出music数组中的每一个音符,通过quyin函数找到其在对应的quzi数组中的重装值并将其作为定时器的新装值。再根据节拍延时相应的时间,从而播放音乐

 

定时器中断处理,将新装值赋给定时器计时初值,并把beep取反产生方波

4、导航按键AD转换模块

(1)初始化部分

设置ADC_CONTR寄存器,打开ADC电源,启动模数转换器ADC,采用90个时钟周期转换一次的方式,并选择P1.7作为A/D输入,同时使用ADC_RES来存放高8位结果

 

初始化ADC_CONTR为0x8F,ADC_FLAG=0,处理导航电压部分的数据,进行A/D转换,直到转换结束ADC_FLAG=1,跳出while循环。不管是A/D转换完成后由该位申请产生中断,还是由软件查询该标志位A/D转换是否结束,当A/D转换完成后,一定要软件清零。

 

首先通过按键消抖(采用延时消抖的方式),判断是否有按键按下。然后取出高3位再将其右移到低三位,获取A/D转换的高三位值,以消除转换误差,并返回该值,便于后面判断按下的是哪个按键。如果没有按键按下,则返回0x07

 

根据当前A/D转换的结果,对数码管上的数进行改变:如果A/D转换的结果是0x05,则说明此时按下的是上键,对应的数字段选信号加1(对应duanxuan数组中显示的数字加一);如果A/D转换的结果是0x02,则说明此时按下的是下键,对应的数字段选信号减1(对应duanxuan数组中显示的数字减一)。

 

4、串口通信模块

(1)串口初始化部分

 

(2)串口中断程序

TI:发送中断标志位,当发送完8位数据后,TI由硬件置位;TI=0,时,可申请中断,也可供软件查询用,在任何方式都必须由软件清除TI;

RI:接收中断标志位,在方式0中,接受完8位数据后,有硬件置位;在其它方式中,在接受停止位的中间,由硬件置位。RI=1时,可申请中断,也可供软件查询用,在任何方式都必须由软件清除RI;

5、主函数部分

首先对各参数进行初始化设置。然后进入while循环,当按下按键KEY2或振动传感器受到振动时,游戏开始。

数码管初始显示0,剩下次数为3。拨动导航按键,通过A/D转换获取相应的AD值从而改变数码管上显示的次数。按下KEY1确认,调用display函数判断大小关系,如果相等,则蜂鸣器响起一段音乐。

如果猜3次以后仍然没有猜对,则数码管跳0,按下KEY2后又可以重新开始游戏。

至此,整个项目的设计也就说明完毕了。。。。

有任何问题欢迎交流……均为本人原创,引用请留言

猜你喜欢

转载自blog.csdn.net/qq_42372980/article/details/82698765