目录

前置模块

方案

功能选择控制

初始化

按键检测

结构体

按键扫描函数

扫描

旋转编码器

功能选择

按键部分

旋转编码器部分

功能选择实现

RDA5807M

初始化

结构体

初始化

数码管

初始化

其他

功放开关

成品


前置模块

8位8段数码管(74HC595)【软件部分】https://blog.csdn.net/m0_57585228/article/details/124577274

数控收音机(硬件设计)https://blog.csdn.net/m0_57585228/article/details/126060943RDA5807M收音机芯片驱动https://blog.csdn.net/m0_57585228/article/details/125940042旋转编码器(EC11)https://blog.csdn.net/m0_57585228/article/details/125458070

方案

使用stm32f103c6t6作为主控,RDA5807M作为收音芯片,使用数码管进行显示,配合按键和旋转编码器作为控制

功能选择控制

初始化

按键检测需要定时器,这里和数码管扫描的定时器合用,为2ms中断触发

注意在定时器初始化函数里打开定时器和中断

  HAL_TIM_Base_Start_IT(&htim2);HAL_TIM_Base_Start(&htim2);

按键检测

结构体

typedef struct
{GPIO_TypeDef *GPIOx;uint16_t GPIO_Pin;uint8_t ins;uint8_t bool;uint8_t i;
} Key_Struct;

不同的按键有不同的GPIO

ins是定时器扫描时用于指示的状态机

bool是按键状态

i是计数值,用于消抖

这是用到的按键

Key_Struct Key_AMP = {GPIOA, GPIO_PIN_4, 0, 0, 0};
Key_Struct Key_FUNCTION = {GPIOA, GPIO_PIN_7, 0, 0, 0};
Key_Struct Key_DETERMINE = {GPIOA, GPIO_PIN_8, 0, 0, 0};
Key_Struct Key_EC11 = {GPIOB, GPIO_PIN_4, 0, 0, 0};

按键扫描函数

有按键按下和松开的两个回调函数

/*** @brief 键盘扫描* @param Key:键盘结构体地址* @param Down:按键按下的回调函数* @param Up:按键弹起的回调函数* @return 无* @author HZ12138* @date 2022-07-29 15:46:00*/
void Key_Scan(Key_Struct *Key, void (*Down)(void), void (*Up)(void))
{if (HAL_GPIO_ReadPin(Key->GPIOx, Key->GPIO_Pin) == GPIO_PIN_RESET && Key->ins == 0){Key->i++;if (Key->i > 10){Key->i = 0;Key->ins = 1;Key->bool = 1;Down();}}else if (HAL_GPIO_ReadPin(Key->GPIOx, Key->GPIO_Pin) == GPIO_PIN_SET && Key->ins == 1){Key->i++;if (Key->i > 10){Key->i = 0;Key->ins = 0;Key->bool = 0;Up();}}
}

扫描

在2ms的定时器中断里进行扫描

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim == &htim2){if (Key_SW){Function_Action();Key_Scan(&Key_AMP, AMP_Change, air);Key_Scan(&Key_FUNCTION, Function_Change, air);Key_Scan(&Key_EC11, EC11_Change, air);Key_Scan(&Key_DETERMINE, DETERMINE, air);}Tube_Send_Scan(Tube_Val, Tube_Spot_P);}else if (htim == &htim3){if (Key_SW)check_R_D();}
}

旋转编码器

需要外部中断和一个GPIO上拉输入模式

之后在外部中断回调函数中调用即可

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if (GPIO_Pin == GPIO_PIN_0){EC11_Decode(EC11_Change_Up, EC11_Change_Down);}
}

功能选择

我设计的功能是按下选择按键时更改音量,电台,频率的选择

按下旋转编码器的按键时更改频率选择的位数(个位十位百位等)

转动旋转编码器更改数值

按下确定按键将数据发送给收音机芯片

因此设置了1个用于指示现在所处的功能的数据

1个用于指示当前频率位置的数据

按键部分

也就是这个结构体里的

uint8_t function_ins;

uint8_t Freq_ins;

typedef struct
{uint8_t function_ins;uint8_t volume;uint8_t radio_station_num;uint16_t Freq;uint8_t Freq_ins;
} MY_Struct;

这个是更改功能指示,进入音量设置和频率设置时先读取芯片里的设置数据,避免出现问题

/*** @brief 功能选择改变函数(按键触发)* @param 无* @return 无* @author HZ12138* @date 2022-07-29 15:50:59*/
void Function_Change(void)
{//改变指示的值MY.function_ins++;if (MY.function_ins > 2)MY.function_ins = 0;//根据功能更新需要的数据if (MY.function_ins == 0){MY.volume = RDA5807M_Read_Reg(0x05) & 0xf;}else if (MY.function_ins == 2){MY.Freq_ins = 0;MY.Freq = RDA5807M_Read_Freq();}check_R_D();
}

这个是更改频率选则的位置

/*** @brief 旋转编码器按键(改变频率的设定值)* @param 无* @return 无* @author HZ12138* @date 2022-07-29 16:13:47*/
void EC11_Change(void)
{MY.Freq_ins++;if (MY.Freq_ins > 3)MY.Freq_ins = 0;
}

旋转编码器部分

上面的是改变标志,这里需要根据标志改变数据

在音量和电台时只需要观察function_ins即可

在频率改变时需要改变function_insFreq_ins两个标志

因为增加和减少有且仅有符号不同(一个是自加,一个是自减)

因此将其放入同一个函数里,根据传入的值进行调用

另外因为有些数据使用的是无符号型,因此在处理0时需要注意避免越位

/*** @brief 旋转编码器实现* @param bool:0增加 1减少* @return 无* @author HZ12138* @date 2022-07-29 16:12:23*/
void EC11_Achive(uint8_t bool)
{if (MY.function_ins == 0){                       //音量int zj = MY.volume; //避免无负数问题if (bool == 0)zj++;else if (bool == 1)zj--;if (zj >= 15)zj = 15;else if (zj <= 0)zj = 0;MY.volume = zj;}else if (MY.function_ins == 1){                                  //电台int zj = MY.radio_station_num; //避免无负数问题if (bool == 0)zj++;else if (bool == 1)zj--;if (zj <= 0)zj = 0;if (zj >= radio_station_Len)zj = radio_station_Len;MY.radio_station_num = zj;MY.Freq = RDA5807M_RadioStadion_Freq[MY.radio_station_num];}else if (MY.function_ins == 2){ //频率int zj = 1;F_A_Freq_ins = 0; //开始时从最低位置开始F_A_Freq_js = 0;  //更改后从亮开始闪烁//跟据选择增加频率if (bool == 0)zj = 1;else if (bool == 1)zj = -1;if (MY.Freq_ins == 0)MY.Freq += zj * 10;else if (MY.Freq_ins == 1)MY.Freq += zj * 100;else if (MY.Freq_ins == 2)MY.Freq += zj * 1000;else if (MY.Freq_ins == 3)MY.Freq += zj * 10000;//范围限制if (MY.Freq >= 10800)MY.Freq = 10800;else if (MY.Freq <= 7600)MY.Freq = 7600;}
}
/*** @brief 旋转编码器增加* @param 无* @return 无* @author HZ12138* @date 2022-07-29 16:06:14*/
void EC11_Change_Up(void)
{EC11_Achive(0);
}
/*** @brief 旋转编码器减少* @param 无* @return 无* @author HZ12138* @date 2022-07-29 16:08:29*/
void EC11_Change_Down(void)
{EC11_Achive(1);
}

功能选择实现

读取标志位function_ins后将结构体中的数据放入数码管的输出缓冲区里即可

将各个位置的数据分离开来放入数码管输出缓冲区

/*** @brief 功能选择实现函数(定时器扫描)* @param 无* @return 无* @author HZ12138* @date 2022-07-29 15:55:51*/
void Function_Action(void)
{if (MY.function_ins == 0){ //音量Tube_Val[0] = Tube_Lest[MY.volume / 10 % 10];Tube_Val[1] = Tube_Lest[MY.volume % 10];for (int i = 2; i <= 7; i++)Tube_Val[i] = Tube_Bleak;Tube_Spot_P = 0xff;}else if (MY.function_ins == 1){ //电台for (int i = 0; i <= 1; i++)Tube_Val[i] = Tube_Bleak;Tube_Val[2] = Tube_Lest[MY.radio_station_num / 10 % 10];Tube_Val[3] = Tube_Lest[MY.radio_station_num % 10];MY.Freq = RDA5807M_RadioStadion_Freq[MY.radio_station_num];Tube_Val[4] = Tube_Lest[MY.Freq / 10000 % 10];Tube_Val[5] = Tube_Lest[MY.Freq / 1000 % 10];Tube_Val[6] = Tube_Lest[MY.Freq / 100 % 10];Tube_Val[7] = Tube_Lest[MY.Freq / 10 % 10];Tube_Spot_P = 6;}else if (MY.function_ins == 2){ //频率//闪烁计时F_A_Freq_js++;if (F_A_Freq_js > 250){if (F_A_Freq_ins == 0)F_A_Freq_ins = 1;else if (F_A_Freq_ins == 1)F_A_Freq_ins = 0;F_A_Freq_js = 0;}//前面变黑for (int i = 0; i <= 3; i++)Tube_Val[i] = Tube_Bleak;//更新数据到数码管Tube_Val[4] = Tube_Lest[MY.Freq / 10000 % 10];Tube_Val[5] = Tube_Lest[MY.Freq / 1000 % 10];Tube_Val[6] = Tube_Lest[MY.Freq / 100 % 10];Tube_Val[7] = Tube_Lest[MY.Freq / 10 % 10];//闪烁实现if (F_A_Freq_ins == 1){Tube_Val[7 - MY.Freq_ins] = Tube_Bleak;}//小数点Tube_Spot_P = 6;}
}

另外在频率选择部分做了选中的频率位数进行闪烁的功能,使用了计数和指示两个数据

int F_A_Freq_js = 0;            //频率闪烁计时
int F_A_Freq_ins = 0;           //频率闪烁状态

这段函数放在定时器中断(2ms)里进行,之后调用数码管显示函数进行输出即可

RDA5807M

初始化

这个芯片的硬件I2C无法使用(咱也不知道为啥)

因此使用软件模拟I2C

需要:
2个GPIO,开漏浮空输出(电路设计时以加上拉电阻)

扫描指示灯时需要一个1s的定时器中断

注意在定时器初始化函数里打开定时器和中断

  HAL_TIM_Base_Start_IT(&htim3);HAL_TIM_Base_Start(&htim3);

结构体

为了方便使用,建立了一个结构体

typedef struct
{uint8_t function_ins;uint8_t volume;uint8_t radio_station_num;uint16_t Freq;uint8_t Freq_ins;
} MY_Struct;

在这个部分中用到的是

uint8_t volume;//音量
uint8_t radio_station_num;//电台好
uint16_t Freq;//频率

音量的取值范围是0-15

电台号是上电时搜索得到的

频率值单位是MHz*100,如106.7=>10670

初始化

radio_station_Len是个全局变量

这些代码均在程序开头

uint8_t radio_station_Len = 10; //电台数量

如模块介绍中所言,进行初始化,搜索并获取电台数量

  RDA5807M_init();HAL_Delay(500);RDA5807M_Set_Volume(10);HAL_Delay(50);radio_station_Len = RDA5807M_Search_ALL_Freq() - 1;RDA5807M_Set_Freq(10670);

一开始的时候是按键和功放禁用的,等待初始化完成后才打开按键和功放

之后检测当前频率是否是电台并改变指示灯

  Key_SW = 1;//按键启用AMP_EN(1);//启用功放check_R_D();//检测是否是电台

中断回调函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim == &htim2){if (Key_SW){Function_Action();Key_Scan(&Key_AMP, AMP_Change, air);Key_Scan(&Key_FUNCTION, Function_Change, air);Key_Scan(&Key_EC11, EC11_Change, air);Key_Scan(&Key_DETERMINE, DETERMINE, air);}Tube_Send_Scan(Tube_Val, Tube_Spot_P);}else if (htim == &htim3){if (Key_SW)check_R_D();}
}

数码管

初始化

需要3个GPIO 推挽上拉输出 最高等级

还有一个2ms定时器中断,和按键扫描连用,这边不需要设置了

其他

功放开关

功放是通过一个mos管进行控制的

/*** @brief 功放开关* @param 无* @return 无* @author HZ12138* @date 2022-07-29 15:50:28*/
void AMP_Change(void)
{if (HAL_GPIO_ReadPin(AMP_EN_GPIO_Port, AMP_EN_Pin) == GPIO_PIN_RESET)HAL_GPIO_WritePin(AMP_EN_GPIO_Port, AMP_EN_Pin, GPIO_PIN_SET);else if (HAL_GPIO_ReadPin(AMP_EN_GPIO_Port, AMP_EN_Pin) == GPIO_PIN_SET)HAL_GPIO_WritePin(AMP_EN_GPIO_Port, AMP_EN_Pin, GPIO_PIN_RESET);
}

成品

收音机

githubhttps://github.com/HZ1213825/HAL_STM32_Radio

【STM32】【HAL库】【实用制作】数控收音机(软件设计)相关推荐

  1. 硬石YS-F1Pro开发板HAL库例程持续更新\2. 软件设计之高级裸机例程(HAL库版本)\YSF1_HAL-121. MH-Z14A二氧化碳传感器模块

    /**   ******************************************************************************   *             ...

  2. STM32 HAL库

    STM32 HAL库 第三章 MDK5 软件入门 bug解决 关键文件介绍 程序仿真 User Keywords 语法提示 代码编辑/查看技巧 第四章 STM32F1 基础知识入门 MDK 下 C 语 ...

  3. stm32+HAL库制作转速仪

    stm32+HAL库制作转速仪 前言 电机在运行过程中,需要实时检测其转速的稳定性,有效反映电机的运行情况. 本文介绍了基于stm32的转速仪的设计,可以用光电门传感器和红外对管传感器测量,可以设置选 ...

  4. 【STM32】标准库与HAL库对照学习教程十三--软件IIC控制AT24C02

    [STM32]标准库与HAL库对照学习教程十三--软件IIC控制AT24C02 一.前言 二.准备工作 三.AT24C02(EEPROM)介绍 1.AT24C02简介 2.引脚功能 3.设备地址 四. ...

  5. STM32 HAL库、标准外设库、LL库(STM32 Embedded Software)

    STM32 Embedded Software 工作以来一直使用ST的STM32系列芯片,ST为开发者提供了非常方便的开发库.到目前为止,有标准外设库(STD库).HAL库.LL库 三种.前两者都是常 ...

  6. STM32 HAL库学习笔记1-HAL库简介

    STM32 HAL库学习笔记1-HAL库简介 HAL库 SPL 库 和 HAL 库两者相互独立,互不兼容.几种库的比较如下 目前几种库对不同芯片的支持情况如下 ST 中文官网上有一篇<关于ST库 ...

  7. 【08】STM32·HAL库开发-HAL库介绍 | STM32Cube固件库介绍 | HAL库框架结构 | 如何使用HAL库及使用注意事项

    目录 1.初识HAL库(了解) 1.1CMSIS简介 1.2HAL库简介 2.STM32Cube固件包浅析(了解) 2.1如何获取STM32Cube固件包? 2.2STM32Cube固件包文件夹简介 ...

  8. 温湿度传感器驱动SHT85 单片机STM32 HAL库

    功能介绍:读取传感器SHT85数据,转换成温度.湿度 .饱和水蒸气含量. 注意事项: SDA脚设置为开漏输出,外部上拉电阻10k.或者设置成推挽,软件切换SDA输入输出. 调试时可适当加长延时时间. ...

  9. STM32 HAL库学习笔记4-SPI

    STM32 HAL库学习笔记4-SPI 前言 一.SPI协议简介 SPI物理层 SPI协议层 1.基本通讯过程 2. 通讯的起始和停止信号 3. 数据有效性 4. CPOL/CPHA 及通讯模式 二. ...

  10. STM32 HAL库实现编码器测速

    STM32 HAL库实现编码器测速 (还开了串口1用来调试,下文没写:然后那个short的用法就是看平衡小车之家(就是喵呜实验室的文档里头的,用法确实惊艳),文末贴了工程) 编码器接口模式 TI1和T ...

最新文章

  1. jmeter实现多并发
  2. 【图解】算法原理!通俗理解机器学习算法
  3. 使用BeanUtils.copyProperties进行对象之间的属性赋值
  4. ubuntu Mysql乱码解决
  5. Reactive Extensions 相见恨晚的Rx.Net
  6. SpringCloud(笔记)
  7. 第十二节:深究内核模式锁的使用场景(自动事件锁、手动事件锁、信号量、互斥锁、读写锁、动态锁)
  8. (4)计数器systemverilog与VHDL编码
  9. JSP中文件上传的关键步骤
  10. oracle的odac dll,.NET2.0中施用最少的ODAC动态库文件连接Oracle数据库
  11. win7安全模式卡在Classpnp.sys文件的解决办法
  12. 知识分享:移动设备的安全管理策略和方法
  13. 图解HTTP读书笔记
  14. 英语中名词复数读法(清辅音、浊辅音)
  15. NIOS II 15:AD7606共享SDRAM
  16. QoS(Quality of Service)服务质量【转自微信公众号开源Linux】
  17. 在前端layui项目中使用ztree
  18. u盘里的文件不见了怎么办?怎么恢复数据?
  19. 《Unity游戏优化》笔记(4)[21/02/05_周五][P29_46]
  20. React Native加载动画,lottie-web 将json解析成动画

热门文章

  1. 西门子840d高级编程手册_840D NC 高级编程简单介绍
  2. python去头去尾.strip()函数用法:
  3. 计算机共享网络授权,怎么设置网络共享与网络访问权限?
  4. 树莓派运行python命令_《树莓派Python编程入门与实战》——2.2 使用Raspbian命令行...
  5. (2)安装配置开发工具-JsDroid引流脚本混合式开发技术系列教程By飞云脚本学院
  6. java随机生成中文名、性别、手机号、住址、email
  7. qemu安卓版免root_用qemu运行一个小小Linux系统
  8. ASP.NET ZERO 学习 —— (4) 开发手册之AccountController
  9. 鹏业安装算量软件一键识别设备操作说明
  10. 阅读笔记4:基于运动想象的脑机接口系统模式识别算法研究