首先能你需要自己做一块最小系统,因为计时精度不需要太高,所以为了节省成本可以省去晶振,直接使用芯片内部的时钟。这是我的原理图采用的是stm32f031c6t6某宝2.5块钱,
硬件部分
然后你可根据你的按键的模具画一块孔位匹配大小相等的pcb,并选用按键,我这边使用的是薄膜按键,当然你也可以使用机械按键或者更好的。最终得到pcb
软件部分
使用stm32cubemx进行辅助开发首先先勾选 “debug serial wire”(这非常重要不然生成的工程烧录后就会出现烧写一次后无法烧写)
然后正常的设置gpio口的模式因为这边我使用的是5x4所以需要使用9个io口,且使用4个io口为输出,5个引脚为输入检测。io口配置为下图
然后在配置串口1实现串口1的收发模式找到串口1 mode选择asynchronous。
并配置相关的串口参数,一般就是改改波特率这是我的串口配置
如何选择clock configuration 进行时钟配置如下图
如何配置定时器进行超时判定,这里使用的是定时器2,这里呢涉及预分频和重装值,通过对时钟进行分频获得我们想要的频率,就是多少秒计一个数,以及什么时候触发计数,什么时候触发重装,触发定时器中断执行我们想要的程序。其中prescaler为预防频值这里是4799,把48mhz进行分频,48000000(48m)/(4799+1)=10000(10khz)根据频率公式:f=1/T ,t=1/f=0.1ms意思是每0.1ms电平变化一次,而我这边选择的模式为上升沿计数,便是下方的counter mode 选择为up。而重装值则为你需要的时间:T / t(计数的时间)-1,如我这边需要300ms 所以得到的period(重装值)就为2999.
配置完后就可以进行代码的生成了选择 project manager,选择你想要的文件夹,和代码编译器
我这里选择的是keil 5 然后点击右上角的 GENERATE CODE 进行生成
然后就可以开始写逻辑功能了
串口配置
首先可以先写个把C语言的printf给放到我们的串口中,不用也可以,然后在stm32f0xx.hal.c中加入下面的代码,串口发送定义到回串口1
#include <stdio.h>
extern UART_HandleTypeDef huart1; //声明串口
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
/**
* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
且在主函数的文件中添加宏定义,好定义一个数组
#define RXBUFFERSIZE 256
char RxBuffer[RXBUFFERSIZE];
并在编译出来的main函数中,添加定时器中断函数。便可进行测试,定时器,与串口发送是否正常
主函数中的while(1)死循环中添加
HAL_TIM_Base_Start_IT(&htim2);//开启定时器2
在main.c文件的末尾添加以下定时器中断函数。
/*******************定时器中断*******/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM2)
{
printf("test,test\n");
__HAL_TIM_CLEAR_FLAG(&htim2,TIM_SR_UIF);//清除tim2的中断标志位
}
}
烧录到芯片后,便会定时发送 test ,我这便为300ms发送一次,倘若因为串口发送太快,亦可使用吧重装值preiod 调到29999,使其3s发送一次,便可大概知道代码是否正常。
代码段在以下此段中断period的值
当成功后便可开始写
按键键测
按键扫描有许多种写法,如比较老实的使用 :if else if 或者使用 获取io寄存器的值进行取值与swich判断便可(当然你要明白他代表的意义)
要写逻辑,首先呢便要搞清楚你需要的逻辑,按键矩阵按键扫描方式我这里有两种,(当然会有其他我没想到的方式)我这 写的有 :
方法一,很简单通过单独对每一行进行输出,并进行io口的扫描,得到你输出的行数,与扫描列得的列数可知道几行几列。并赋值(简单)当然你也可以通过寄存器简化,代码就不用写这么多,这就是为什么说寄存器运行比(不管是标准库还是hal库,不接受反驳)库函数快的原因。
实现代码为
char KeyPad_Scan()
{
u16 readvalue = 0;
char data1=0;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_RESET);//
HAL_Delay(2);
readvalue =GPIOA->IDR; //读取gpioA所有的引脚
readvalue &= 0x01f0; //保留低8位的高5位的值
if(readvalue != 0x01f0) //高5位引脚有一个被按下
{
HAL_Delay(5);
readvalue =GPIOA->IDR; //读取gpioA所有的引脚
readvalue &= 0x01f0; //保留低8位的值
if(readvalue != 0x01f0) //高5位引脚有一个被按下
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_PIN_SET);//
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_Delay(2);