STM32开发,串口和PC机通信(串口中断、FIFO机制),安富莱+正点原子程序合并
STM32开发,串口和PC机通信(串口中断、FIFO机制),安富莱+正点原子程序合并
1 概述
实验的代码已经上传,无需积分。
1.1 资源概述
开发板:正点原子STM32F103 Nano开发板
CUBEMX版本:1.3.0
MDK版本:5.27
主控芯片型号:STM32F103RBT6
1.2 实现功能
1,USB连接到电脑。运行串口 软件。
2,操作开发板上的按键,可以在PC机串口软件上观察到变化的数字。对应的LED灯翻转。
3,在计算机键盘上输入数字键1、2、3、4可以分别控制开发板上的4个LED指示灯。
2 软件实现
2.1实现步骤
此次调试时发现安富莱自带的bsp_key并不是太好用,也可能时我没改好,怎么改,有两个按键都无法对应上,另外两个对应上的按键逻辑很奇怪。于是舍弃安富莱的按键程序,将正点原子的按键程序移植过来。移植过程如下:
正点原子键盘支持包:key.c,key.h
安富莱键盘支持包:bsp _key.c,bsp_key.h
1,同时打开安富莱的工程和正点原子的工程,分别编译通过。
2,将正点原子的key.c文件和Key.h文件直接塞到安富莱的工程中。
3,通过正点原子的工程分别找到key文件中用到的函数的定义以及相关宏定义,打开对应的文件,copy。
4,将copy的内容粘贴到安富莱工程中的key文件中。
5,编译,并将错误一个个找到原因并解决。
6,在安富莱工程中,定位到bsp_key文件,查找里边的函数使用处,将使用到的函数,全部替换为新增加的正点原子key文件中的函数。
7,编译,解决报错问题,直至没有报错。
8,从安富莱工程中移除bsp_key文件,再次编译,直至改掉所有error和warning。
9,重新定义正点原子的GPIO口等,修改安富莱相关端口定义,不局限于GPIO口,串口等。
上述步骤切记要一步一步来,慢慢改,一步到位很容易出错,且错误一环套一环非常难查找。反而耽误时间。
2.2 main()函数代码
main()函数代码如下,键盘相关部分函数借用于正点原子,其它使用安富莱自己的函数。
/*
*********************************************************************************************************
*
* 模块名称 : 主程序入口
* 文件名称 : main.c
* 版 本 : V1.0
* 说 明 : 串口通信例子,和PC机超级终端软件进行交互
* 修改记录 :
* 版本号 日期 作者 说明
* V1.0 2015-08-30 armfly 首发
*
* Copyright (C), 2015-2016, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*/
#include "bsp.h" /* 底层硬件驱动 */
/* 定义例程名和例程发布日期 */
#define EXAMPLE_NAME "V4-003_串口和PC机通信(串口中断、FIFO机制)"
#define EXAMPLE_DATE "2020-04-24"
#define DEMO_VER "1.0"
#define key_mode 0 /*0为按键不连续,1为按键连续*/
static void PrintfLogo(void);
static void PrintfHelp(void);
/*
*********************************************************************************************************
* 函 数 名: main
* 功能说明: c程序入口
* 形 参:无
* 返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{
uint8_t ucKeyCode;
int16_t count = 0;
uint8_t fRefresh = 0;
uint8_t read;
/*
ST固件库中的启动文件已经执行了 SystemInit() 函数,该函数在 system_stm32f4xx.c 文件,主要功能是
配置CPU系统的时钟,内部Flash访问时序,配置FSMC用于外部SRAM
*/
bsp_Init(); /* 硬件初始化 */
PrintfLogo(); /* 打印例程名称和版本等信息 */
PrintfHelp(); /* 打印操作提示 */
fRefresh = 1;
/* 主程序大循环 */
while (1)
{
bsp_Idle(); /* CPU空闲时执行的函数,在 bsp.c */
/* 摇杆左右键(上下键)控制LED流动 */
if (fRefresh)
{
fRefresh = 0;
#if 0 /* 可以用 printf打印数据到串口 */
printf("count = %6d \r\n", count);
#else /* 也可以用 sprintf先输出到一个buf,然后在发送到串口 */
{
char buf[64];
sprintf(buf, "count = %6d \r\n", count);
comSendBuf(COM1, (uint8_t *)buf, strlen(buf));
}
#endif
}
if (comGetChar(COM1, &read))
{
switch (read)
{
case '1':
bsp_LedToggle(1);
break;
case '2':
bsp_LedToggle(2);
break;
case '3':
bsp_LedToggle(3);
break;
case '4':
bsp_LedToggle(4);
break;
}
}
/* 处理按键事件 */
ucKeyCode = KEY_Scan(key_mode);
if (ucKeyCode != 0)
{
/* 有键按下 */
switch (ucKeyCode)
{
case KEY0_PRES: /* 按键0被按下 */
count-=10;
fRefresh = 1;
bsp_LedToggle(1);
break;
case KEY1_PRES: /* 按键1按下 */
count--;
fRefresh = 1;
bsp_LedToggle(2);
break;
case KEY2_PRES: /* 按键2按下 */
count+=10;
fRefresh = 1;
bsp_LedToggle(3);
break;
case WKUP_PRES: /* 按键WKUP按下 */
count++;
fRefresh = 1;
bsp_LedToggle(4);
break;
default:
break;
}
}
}
}
/*
*********************************************************************************************************
* 函 数 名: PrintfHelp
* 功能说明: 打印操作提示
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
static void PrintfHelp(void)
{
printf("操作提示:\r\n");
printf("1. 摇杆控制count计数值\r\n");
printf(" 上键 = +1\r\n");
printf(" 下键 = -1\r\n");
printf(" 左键 = -10\r\n");
printf(" 右键 = +10\r\n");
printf("2. PC上输入数字1-4控制开发板上的LED指示灯\r\n");
}
/*
*********************************************************************************************************
* 函 数 名: PrintfLogo
* 功能说明: 打印例程名称和例程发布日期, 接上串口线后,打开PC机的超级终端软件可以观察结果
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
static void PrintfLogo(void)
{
printf("*************************************************************\r\n");
printf("* 例程名称 : %s\r\n", EXAMPLE_NAME); /* 打印例程名称 */
printf("* 例程版本 : %s\r\n", DEMO_VER); /* 打印例程版本 */
printf("* 发布日期 : %s\r\n", EXAMPLE_DATE); /* 打印例程日期 */
/* 打印ST固件库版本,宏定义在 stm32f4xx.h 文件 */
printf("* 固件库版本 : %d.%d.%d\r\n", __STM32F10X_STDPERIPH_VERSION_MAIN,
__STM32F10X_STDPERIPH_VERSION_SUB1,__STM32F10X_STDPERIPH_VERSION_SUB2);
/* 打印 CMSIS 版本. 宏定义在 core_cm4.h 文件 */
printf("* CMSIS版本 : %X.%02X\r\n", __CM3_CMSIS_VERSION_MAIN, __CM3_CMSIS_VERSION_SUB);
printf("* \r\n"); /* 打印一行空格 */
printf("* QQ : 1295744630 \r\n");
printf("* Email : aaa@qq.com \r\n");
printf("* Copyright www.armfly.com 安富莱电子\r\n");
printf("*************************************************************\r\n");
}
/***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/
2.3 正点原子键盘连按和不连按函数说明
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;//按键按松开标志
if(mode)key_up=1; //支持连按
if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))
{
bsp_DelayMS(10);//去抖动
key_up=0;
if(KEY0==0)return KEY0_PRES;
else if(KEY1==0)return KEY1_PRES;
else if(KEY2==0)return KEY2_PRES;
else if(WK_UP==1)return WKUP_PRES;
}else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)key_up=1;
return 0;// 无按键按下
}
第三行,定义了一个静态变量,static,这个函数在程序运行时,第一次调用函数时,后面跟着key_up=1才有效。后面不管调用了多少次此定义的key_up=1不再生效,即使被其它地方赋值了其它数。通过这个功能实现了连按和不连按的功能。实验证实,当static这个类型删除后,不管mode是0还是1,都是连按。
3 实验结果
串口打印结果
发送1234时,全部的四个灯点亮
再次发送1234时,四个灯全灭
按按键时,对应的LED状态会进行翻转