嵌入式开发学习之--用蜂鸣器来传递摩斯码

简介: 嵌入式开发学习之--用蜂鸣器来传递摩斯码

嵌入式开发学习之--用蜂鸣器来传递摩斯码


前言

 在点亮led灯之后,接连写了两篇理论,更多的是力求自己学习旅程的完整吧,总觉得没多大意义。从今天开始,结合开发板开始搞实验,毕竟实战是检验一切的标准。一起学习的小伙伴如果有什么好的想法,可以留言,我们一起来完成。

一、项目概况

1.1项目需求

 根据输入的情报,让蜂鸣器按照摩斯码的加密方式发出声音,用户通过蜂鸣器发出的声音能准确的写出输入的情报,就算成功。

1.2项目来源

作者脑洞。

1.3项目开发环境

软件:keil5;

硬件:野火挑战者开发板。

1.4项目意义

 为情报人员传递信息,可以在影视剧,密室逃脱等场景中作为道具使用。

二、开发步骤

2.1了解什么是摩斯码

 作为嵌入式开发,首先你要了解的是你开发的东西是个什么,我们既然要做摩斯码传递,那么就要了解什么是摩斯码。

 通过百度可以知道摩尔斯电码(Morse code)也被称作摩斯密码,是一种时通时断的信号代码,通过不同的排列顺序来表达不同的英文字母、数字和标点符号。它发明于1837年,是一种早期的数字化通信形式。不同于现代化的数字通讯,摩尔斯电码只使用零和一两种状态的二进制代码,它的代码包括五种:短促的点信号“・”,保持一定时间的长信号“—”,表示点和划之间的停顿、每个词之间中等的停顿,以及句子之间长的停顿。划一般是三个点的长度;点划之间的间隔是一个点的长度;字元之间的间隔就是三个点的长度;而单词之间的间隔是七个点的长度。

也就是说,我们需要通过蜂鸣器模拟出这几种情况。

2.2构建项目流程图

 这个就比较考验个人了,也是我一直想实战的原因,不同的人都会有不同的思路,这里分享一下我的思路,算是抛砖引玉吧。

 首先从项目需求来看,要有一个输入情报,接着根据摩斯电码表,将输入的情报拆解成电码表的样式,然后再通过蜂鸣器进行输出。

image.png

2.3找到合适的模板

 这里我们就用野火的工程模板,找到打开后简单编译一下。0错误,说明可以用。

2.4增加文件

 根据项目接着新添加几个文件:

 1.上层应用,主要是用来定义、存储上层应用所用到的函数变量。

 2.底层硬件,主要根据所应用到的硬件资源创建。

 创建文件时可以县创建记事本,然后修改尾缀和名字。

创建了4个文件,app.c、app.h、beep.c、beep.h。

添加进工程:

基本的工程框架已经建好,下一步就是写代码。

2.5添加代码

 我们把代码分为三部分,蜂鸣器,摩斯码,main函数。

 首先我们先初始化需要用到的硬件蜂鸣器。

 按照之前我们处理led灯的思路,首先我们要看电路图,找到蜂鸣器。

通过电路图我们可以看出,开发板的蜂鸣器是通过PI11引脚的高低控制是否有电。也就是我们要像配置led灯一样配置蜂鸣器。

蜂鸣器代码如下(示例):

beep.c

#include "stm32f4xx.h"
#include "beep.h"
void BEEP_GPIO_Config(void)
{   
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd( BEEP_GPIO_CLK, ENABLE);                                  
  GPIO_InitStructure.GPIO_Pin = BEEP_GPIO_PIN;  
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;     
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
  GPIO_Init(BEEP_GPIO_PORT, &GPIO_InitStructure);        
  GPIO_ResetBits(BEEP_GPIO_PORT, BEEP_GPIO_PIN);   
}

beep.h

#ifndef __BEEP_H
#define __BEEP_H
#include "stm32f4xx.h"
#define BEEP_GPIO_PORT      GPIOI                  
#define BEEP_GPIO_CLK       RCC_AHB1Periph_GPIOI  
#define BEEP_GPIO_PIN       GPIO_Pin_11          
#define ON  1
#define OFF 0
#define BEEP(a) if (a)  \
          GPIO_SetBits(BEEP_GPIO_PORT,BEEP_GPIO_PIN);\
          else    \
          GPIO_ResetBits(BEEP_GPIO_PIN)
#define digitalHi(p,i)      {p->BSRRL=i;}         
#define digitalLo(p,i)      {p->BSRRH=i;}       
#define digitalToggle(p,i)  {p->ODR ^=i;}     
#define BEEP_TOGGLE   digitalToggle(BEEP_GPIO_PORT,BEEP_GPIO_PIN)
#define BEEP_OFF      digitalLo(BEEP_GPIO_PORT,BEEP_GPIO_PIN)
#define BEEP_ON       digitalHi(BEEP_GPIO_PORT,BEEP_GPIO_PIN)
void BEEP_GPIO_Config(void);
#endif

简单解读一下,通过BEEP_GPIO_Config这个函数对蜂鸣器控制引脚PI11进行配置,然后将参数定义成宏定义,这样后期想换也十分方便;就将关闭和打开蜂鸣器的函数分别定义成BEEP_OFF和BEEP_ON,这样使用时十分方便。

 接着处理莫斯码函数,应该单独定义出摩斯码相关文件更合适,这里直接写在app文件里了。

app.c

代码如下(示例):

#include "stm32f4xx.h"
#include "app.h"
_morse_code morse_code;
uint8_t morse_table_1[Ms_Table_num][Ms_Table_long]={" 0000000","A102","B2010101","C2010201","D20101","E1","F1010201","G20201", \
                               "H1010101","I101","J1020202","K20102","L1020101","M202","N201",\
                               "O20202","P1020201","Q2020102","R10201","S10101","T2",\
                               "U10102","V1010102","W10202","X2010102","Y2010202","Z2020101"};
void delay_ms(uint32_t time)
{ 
  int i;
  for(i=0;i<(SYS_FRE/1000)*time;i++){
  }
}                            
//³õʼ»¯app
int app_init()
{
}
uint8_t infor_translate_morse(uint8_t infor,uint8_t morse,uint32_t size)
{
  return morse;
}
uint8_t morse_translate_beep(uint8_t_morse)
{
  return 0;
}

app.h

代码如下(示例):

#ifndef __APP_H
#define __APP_H
#include "stm32f4xx.h"
#define Ms    morse_code
#define Ms_T  morse_table_1
#define Ms_Table_num 50
#define Ms_Table_long 20
#define Ms_Pause "0"
#define Ms_Short "1"
#define Ms_Long  "2"
#define Morse_Dalay_Time                 50   
#define Morse_Pause_Time                 Morse_Dalay_Time*1
#define Morse_Pause_OF_Letter_Time       Morse_Dalay_Time*3
#define Morse_Pause_OF_Word_Time       Morse_Dalay_Time*1
#define Morse_Short_Time                 Morse_Dalay_Time*1 
#define Morse_Long_Time                  Morse_Dalay_Time*3
#define SYS_FRE   72000000
typedef struct MORSE_CODE{
uint8_t* morse_table[50];
uint8_t* morse_in;
uint8_t* morse_out; 
}_morse_code;
extern _morse_code morse_code;
extern uint8_t morse_table_1[Ms_Table_num][Ms_Table_long];
extern void delay_ms(uint32_t time);
#endif

简单解读一下,我的思路将摩斯码转换成字符串,然后对字符串进行操作,间隔是0,点是1,划是2,然后通过2维数组来定义摩斯码,定义的方式字符串首字符是发送字符,后面是其对应的摩斯码,这样进行首字符对比,找到对应字符以后,再对其后面的字符串进行读取并执行相关操作即可。定义时,依旧记得尽量采取宏定义的方式。这里还定义了一个延时函数,延时方式就是通过数数,我们的单片机频率是72M的,也就是1秒中可以数执行72M的操作,那么1ms可以数72000。如果未来更换频率是其它的单片机,这个记得要改。

 最后是main函数,我把最终执行函数写在了一起,其实不是很满意,耦合性太强了,可以划分的更合理。

main.c

代码如下(示例):

#include "stm32f4xx.h"
#include "beep.h"
#include "app.h"
#include <string.h>
int beep_out_morse_data(uint8_t* data,int size)
{
 uint32_t i;
 uint32_t j;
 uint8_t* p;
 uint8_t* q;      
 p=data;                            
  for(i=0;i<size;i++){                  
    for(j=0;j<Ms_Table_num;j++){        
      q=Ms_T[j];
      if(*p==*q){                   
        break;  
      }         
    }
    if(j>=Ms_Table_num){
    }
    while(*q!='\0'){
      q++;
      if(*q=='0'){
        BEEP_OFF; 
        delay_ms(Morse_Pause_Time);
      }else if(*q=='1'){
        BEEP_ON;  
        delay_ms(Morse_Short_Time);       
      }else if(*q=='2'){
        BEEP_ON;  
        delay_ms(Morse_Long_Time);            
      }else if(*q=='3'){
      }else{
      }     
    }
    BEEP_OFF; 
    delay_ms(Morse_Pause_OF_Letter_Time);   
    j=0;
    p++;    
    }
}
int main(void)
{
  uint8_t information[]= "I LOVE YOU";  
  BEEP_GPIO_Config(); 
  morse_code.morse_in=information;  
  while(1){
    beep_out_morse_data(morse_code.morse_in,strlen((const char *)morse_code.morse_in)); 
  }
}

总结

 1.蜂鸣器的配置和led灯思路完全一致,就是一个普通I/O口的配置操作。可以自己写一写复习一下。

 2.注意代码架构,不仅要考虑当前的任务,也要考虑之后的维护,移植,扩展等等。我做的也不是很好,在写这个的时候脑子里多了很多想法,越想越复杂,最后按照自己思路去先做出来再说,后期可以在这个基础上继续补充。

 3.实践是检验真理的唯一标准,多动手写一写,多跑跑代码,将理论转化为实际。

相关文章
|
API
uniapp使用u-checkbox
uniapp使用u-checkbox
919 1
|
12月前
|
Cloud Native 持续交付 云计算
云计算的未来:探索云原生技术的崛起与影响
【10月更文挑战第9天】 在当今数字化转型的浪潮中,云计算已成为推动企业创新和效率提升的关键力量。随着技术的进步和市场需求的演变,一种新兴的技术趋势——云原生,正逐渐崭露头角,引领着云计算进入一个全新的发展阶段。本文将深入探讨云原生的概念、核心原则、关键技术以及它如何改变企业的运营模式和业务策略。通过分析云原生技术的优势、挑战和未来趋势,我们将揭示这一技术变革背后的深层含义,以及它如何塑造未来的数字生态系统。
|
Android开发
不写一行代码(二):实现安卓基于PWM的LED设备驱动
本文介绍了在Android系统中不编写任何代码,通过设备树配置和内核支持的通用PWM LED驱动来实现基于PWM的LED设备驱动,并通过测试命令调整LED亮度级别。
338 0
不写一行代码(二):实现安卓基于PWM的LED设备驱动
WordPress 修改上传文件大小限制
WordPress 修改上传文件大小限制
343 3
|
网络协议 应用服务中间件 Linux
【Nginx】在线安装与离线安装
【Nginx】在线安装与离线安装
611 0
|
XML 缓存 Android开发
QMUI实战(二)—Activity 和 Fragment,我们该选择谁?
在一开始,官方只提供了 Activity 来作为 UI 界面的载体,因此我们也别无选择,只能用它。而在 Android 3.0 后,Fragment 也面世了,它一开始是用于适配平板的,以邮件列表与详情的适配为例,手机端够小,因此开始展示列表,点击进入详情,而平板够大,则可以列表显示在左侧,详情显示在右侧,点击列表只是切换详情。对于这种适配场景,列表页和详情页必须在同一个 Activity 里了,而这便是我所知道的 Fragment 诞生的场景了。
362 0
|
存储 SQL 人工智能
2022云栖精选—达摩院加持下的数据库技术前沿
汪晟 阿里巴巴集团资深技术专家 达摩院数据库与存储实验室系统与安全方向负责人
2022云栖精选—达摩院加持下的数据库技术前沿
|
Linux Windows
如何从虚拟机上的linux使用sz命令传输windows大于4G的文件
如何从虚拟机上的linux使用sz命令传输windows大于4G的文件
920 0
如何从虚拟机上的linux使用sz命令传输windows大于4G的文件
|
人工智能 并行计算 算法
|
消息中间件 存储 缓存
kafka权威指南 第二章第6节 Kafka集群配置与调优
kafka权威指南 第二章第6节 Kafka集群配置与调优
446 0
kafka权威指南 第二章第6节 Kafka集群配置与调优