嵌入式计算机系统设计第五次实验报告

Keil程序仿真 & 算法及性能评估
2022.4.18~2022.4.30
实验环境:个人电脑、Keil、STC-ISP、STC-B学习板、步进电机
实验目的:
任务1:完善实验三(步进电机驱动)。
任务2:在完善实验三基础上,实现蜂鸣器可控发声和指示。
i.Beep模块按分层设计(底层驱动、向应用层提供API函数)
ii.按键模块按分层设计(底层驱动、向应用层提供事件及API函数)
iii.(选做)在Beep模块设计完成基础上,实现播放音乐的功能(参照STCBSP提供的Music模块API)
实验条件:同前
实验内容:

任务1:完善实验三(步进电机驱动)

实验3已完善,详情见实验3

任务2:在完善实验三基础上,实现蜂鸣器可控发声和指示。

(1)Beep模块按分层设计(底层驱动、向应用层提供API函数) 首先定义相关引脚:蜂鸣器的电源引脚在P3.4


编写驱动函数:
将相关引脚设置为推挽模式,并设置好定时器的模式:如下本次蜂鸣器使用的是定时器1,控制定时器的寄存器见操作手册,每个寄存器的功能如下图所示,其中TH1和TL1表示定时器1的初始值(表示T1的高8位和低8位),系统启动后,T1,每个时钟加一,直到溢出后触发定时器中断并重装初始值(这需要模式设置)
所以如图SysClock/(Hz*2)就表示T1需要经过多少次加1才能溢出,然后将这个数值乘上每个时钟周期的时间即可得到,发生一次定时器中断所需要的的时间
(这里T1设置的是12不分频模式1T速度是分频的12倍,所以如果是12T分频模式还需要乘12才是定时器中断一次的时间)
嵌入式计算机系统设计第五次实验报告_第1张图片

利用定时器中断进行蜂鸣器的发声:不断将引脚反转从而达到使蜂鸣器震动发声的效果,beep_time用于控制蜂鸣器发声的时间,当蜂鸣器不发生时需要将引脚置于低电平(减少功耗)
嵌入式计算机系统设计第五次实验报告_第2张图片

设置蜂鸣器属性:设置蜂鸣器发声的频率和时间(通过修改定时器的频率做到)
然后根据频率计算出应该进行中断的次数来控制时间(beep_time 单位10ms)
嵌入式计算机系统设计第五次实验报告_第3张图片

(2)按键模块按分层设计(底层驱动、向应用层提供事件及API函数)

对于按键的引脚而言,原理图如下,所以当key1,2,3按下后相关的引脚电平会为0,抬起时为1,我们可以根据按键电平的跳变来判断按键是抬起还是按下
嵌入式计算机系统设计第五次实验报告_第4张图片

定义引脚和驱动函数:驱动函数只需将相关引脚设置为准双向口来确保可以输出高低电平同时不会因电流过大(如推挽模式)而将引脚烧坏
嵌入式计算机系统设计第五次实验报告_第5张图片

我们定义两个状态:一个当前状态和上一时刻状态,我们可以通过这两个状态的不同来判断按键是否按下或抬起
大致原理如下:
嵌入式计算机系统设计第五次实验报告_第6张图片

这里我使用的是40ms内如果相关按键电平为0的时间超过25ms则我们认为是按键按下状态,否则为抬起状态,相关代码如下:
当判断有按键事件发生时,运行回调函数CallBack,这个函数需要用于自己提供

嵌入式计算机系统设计第五次实验报告_第7张图片

最后获取按键事件状态:在按键获取一次事件后需要将按键事件复位
嵌入式计算机系统设计第五次实验报告_第8张图片

(3)(选做)在Beep模块设计完成基础上,实现播放音乐的功能(参照STCBSP提供的Music模块API)

首先想要播放音乐我们需要通过蜂鸣器发出每一个音调的声音,相关音调的频率如下(因为是使用蜂鸣器模块作为底层,所以这里驱动函数是空的):
在这里插入图片描述

每个字母表示相关音调的7个音节的低中高音(比如C数组前7位表示,C调的低音do、re、mi、fa、so、la、si再后面7位表示中音最后7位高音)
然后我们编写播放音调的函数,变量syl取值为0x11-0x17,0x21-0x27,0x31-0x37,每个字节的高4位表示低中高音,第4位表示音节,所以我们获取相关频率可以按照如图方式进行,然后变量beats表示这个音节的节拍数(取值单位为1/16个节拍,如0x10表示1个节拍),beatsPM表示1分钟的节拍数(比如60就表示一个节拍1s,这个变量用于控制1个节拍的时间),然后我们通过这两个变量计算出蜂鸣器发声的时间(图中公式是为了减少因为除法带来的误差进行化简后的结果)
嵌入式计算机系统设计第五次实验报告_第9张图片

然后我们开始播放音乐:
通常情况下每次取两字节第一个字节表示音节,第二个字节表示节拍
如果遇到控制字符(如修改音调或改变每分钟节拍数)则进行相关的处理,没有遇到的情况如下:播放一次后songsit(用于记录播放位置)加2,播放完成后改变音乐模式为enumModeStop
嵌入式计算机系统设计第五次实验报告_第10张图片

相关控制字符如改变节拍率:改变后跳转songsit到下一个可以播放的字符位置即可,跳转时判断一下是否到歌曲结束部分,其余控制字符同理。
嵌入式计算机系统设计第五次实验报告_第11张图片

设置音乐播放的初始属性:
嵌入式计算机系统设计第五次实验报告_第12张图片

改变音乐播放状态:注意在停止时将变量复位
嵌入式计算机系统设计第五次实验报告_第13张图片

获取音乐播放状态:该函数用于后续对这几个函数进行封装后连续播放音乐
嵌入式计算机系统设计第五次实验报告_第14张图片

最后进行这几个功能的汇总测试:

用“定时器2”及其“中断”控制(无源)蜂鸣器发声,要求发声频率可以改变和显示;

注:发声频率在200~2000Hz范围内;
按键控制发声频率变化(每次变化步长 >= 100Hz);
发声频率在数码管上显示;
步进电机(4个流水灯)快慢随发声频率同步变化。
通过按键控制频率,按键1蜂鸣器将按照设定的频率发声1s,按键2增加频率同时增加电机的运行速度,按键3降低频率同时降低电机的运行速度。
显示部分通过10ms回调实时显示。
具体代码如下图所示
嵌入式计算机系统设计第五次实验报告_第15张图片

完整代码

蜂鸣器头文件

#include "STC15F2K60S2.H"
sbit beep_bit = P3 ^ 4;
unsigned int Hz = 1000;
extern code long int SysClock;
unsigned int beep_time = 0;
void _BeepInit()
{
   
    P3M0 = 0X10; // 保持其他模式不变,P3.4设置为推挽输出
    P3M1 = 0X00;
    beep_bit = 0;

    AUXR |= 0x40; //定时器1工作在1T、16位自动重装初值
    TMOD &= 0x0F; //计算器方式控制高4位控制T1低4位控制T0,这里只控制T1
    TL1 = 65536 - (SysClock / (Hz * 2));
    TH1 = (65536 - SysClock / (Hz * 2)) >> 8; //两者都是T1计数器
    TR1 = 1;                                  //允许T1开始计数
    ET1 = 1;
}
void beep_play(void) interrupt 3
{
   
    if (beep_time)
    {
   
        beep_time--;
        beep_bit = ~beep_bit;
    }
    else
        beep_bit = 0;
}
void _SetBeep(unsigned int hz, unsigned int time)
{
   
    Hz = hz;
    TL1 = 65536 - (SysClock / (Hz * 2));
    TH1 = (65536 - SysClock / (Hz * 2)) >> 8; //两者都是T1计数器
    beep_time = time * (Hz/50);
}

按键头文件

#include "STC15F2K60S2.H"
enum KeyName
{
   
    enumKey1,
    enumKey2,
    enumKey3
}; //按键名
enum KeyActName
{
   
    enumKeyNull,
    enumKeyPress,
    enumKeyRelease,
    enumKeyFail
}; //按键动作名
sbit KEY1 = P3 ^ 2;
sbit KEY2 = P3 ^ 3;
sbit KEY3 = P1 ^ 7;
bit state1 = 1, state2 = 1, state3 = 1; //按键状态1:抬起,0按下
bit Lstate1 = 1, Lstate2 = 1, Lstate3 = 1;
enum KeyActName KeyAct1 = enumKeyNull, KeyAct2 = enumKeyNull, KeyAct3 = enumKeyNull, KeyAct;
unsigned char count = 40;
unsigned char key_num1 = 0, key_num2 = 0, key_num3 = 0;
void Key_Init() //初始化函数
{
   
    // IT1 = 1;
    // IT0 = 1; //下降沿触发
    P3M0 &= 0xf3;
    P3M1 &= 0xf3; // p3.2,p3.3准双向口
    P1M0 &= 0x7f;
    P1M1 &= 0x7f;
    // EX0 = 1;
    // EX1 = 1; //开启INT0,INT1的中断服务
}
void KeyJudge(void (*CallBack)()) // 1ms延时,按键状态改变函数(核心)
{
   
    if (KEY1 == 0)
        key_num1++;
    if (KEY2 == 0)
        key_num2++;
    if (KEY3 == 0)
        key_num3++;
    if (count != 0)
        count--;
    else //改变状态
    {
   
        count = 40;         //复位
        if (key_num1 >= 25) // 40ms内有25ms时间处于按下状态则认为是按下
            state1 = 0; //按下状态
        else
            state1 = 1;     //抬起状态
        if (key_num2 >= 25)
            state2 = 0;     //按下状态
        else
            state2 = 1<

你可能感兴趣的:(嵌入式硬件,单片机)