前言
通过xshell对stm32f103c8t6芯片进行串口调试。
最近发现xshell也可以进行串口调试,但是在数据的输入上会有一些问题。
因为正常的串口调试助手都是统一输入,直接发送,但是xshell不同,正常情况下是字符逐一输入的。
所以在进行串口调试时,需要逐个字符分析计算,最后统一处理。
用xshell调试的优点就是软件优化好,使用起来很舒服。
缺点是,没法看16进制数据;不能自定义数据帧格式;也没有输入框,也显示不了用户输入数据。
整体来说,xshell用于这种串口调试,其实不是很明智的选择。
设计
思路
graph LR A(初始化) B(主函数处理) C(回调函数处理) A --> C C <--> B C --> C初始化之后,回调函数接收用户输入,主函数处理用户输入的数据
同时,因为xshell不能显示用户的输入数据,所以需要在主函数中打印用户输入。
不建议在回调函数中打印,具体原因代码中会有表示。
分析
本来想做成一个类,这样所有的串口都可以同时使用,但是有一说一,C语言实现类确实有点麻烦。
可以用一个结构体保存参数,然后传递到函数中,这个方法要比类简单的多,而且也能实现所有串口都可以使用的功能。但是目前一个串口就够用,就没有实现了,有兴趣的可以自己实现一下。
初始化部分
初始化部分决定了整段代码的相对独立性,所以在初始化时应该输入一个参数,让这个库可以用于任何一个串口。
这个参数应该是串口的决定性参数,如&huart1这样的。
回调函数
回调函数应该做最少的处理,毕竟中断里面做大量计算,太占资源了。
主函数处理
这一部分可以做大量的计算和处理,毕竟主函数可以被打断,不会太耗费资源。
实现
实现这些功能,要解决几个问题
- 输入的命令需要存储下来,方便后面处理。
- 回调函数是运行在中断中,可以做到即时,但是主函数是在while中,不能做到即时相应。
- 需要一个特定的按键来出发判断机制,做对应的命令处理。
特定命令判断
先从最简单的开始,以使用者的习惯来说,回车做为确定符号是很自然的。
退格作为命令输入之后的取消,也是相对合理的。只是在做的时候和正常的取消有点不同。
输入命令的保存
保存采用的是栈的方式,定义一个数组,再定义一个坐标指针,通过坐标指针向数组写入数据。
不同步问题
数据无法完全实时同步,所以就需要一个输出指针。这样虽然输出和输入数据还是不同步,但可以做到延迟响应,不会让数据在输出时丢失。
代码
源码
H文件
/*
* command.h
*
* Created on: May 15, 2024
* Author: yangg
*/
#ifndef COMMAND_H_
#define COMMAND_H_
#include "stm32f1xx_hal.h"
#include "usart.h"
#define COMMAND_STACK_MAX 15//用户自行修改,命令的最大长度,比int16_t的最大范围小即可
void comInit(UART_HandleTypeDef *huart);
void comPrintManage();
void comCallback();
#endif /* COMMAND_H_ */
C文件
/*
* command.c
*
* Created on: May 15, 2024
* Author: yangg
*/
#include "command.h"
UART_HandleTypeDef *_huart;
static uint8_t _comBuff[COMMAND_STACK_MAX];
static uint8_t _temp;
static int16_t _comTop;
static int16_t _comPrint;
void comInit(UART_HandleTypeDef *huart) {
_comTop = -1;
_comPrint = -1;
_huart = huart;
HAL_UART_Receive_IT(_huart, &_temp, 1);
}
void comPrintManage() {
while (_comPrint < _comTop || _comPrint == COMMAND_STACK_MAX - 1) {
if (_comPrint < COMMAND_STACK_MAX - 1) {
_comPrint++;
}
if (_comBuff[_comPrint] == 0x08) {
_comTop = -1;
_comPrint = -1;
HAL_UART_Transmit(_huart, (uint8_t*) "\r\n", 2, 100);
} else if (_comBuff[_comPrint] == 0x0D) {
// TODO 命令处理--------------------------------------------------
_comTop = -1;
_comPrint = -1;
HAL_UART_Transmit(_huart, (uint8_t*) "\r\n", 2, 100);
} else {
if (_comPrint < COMMAND_STACK_MAX - 1) {
HAL_UART_Transmit(_huart, &_comBuff[_comPrint], 1, 100);
} else {
return;//超过最大长度不显示,
}
}
}
}
void comCallback() {
if (_comTop < COMMAND_STACK_MAX - 1) {
_comTop++;
}
_comBuff[_comTop] = _temp;
HAL_UART_Receive_IT(_huart, &_temp, 1);
}
在C文件中的TODO 命令处理
部分可以写自己定义的命令和处理方式。
对退格的处理不是清除一个字符,因为如果清除一个字符,需要每次都对字符串进行刷新。所以对于退格就直接清除掉所有数据了。
示例
主函数
int main(void) {
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
MX_USB_PCD_Init();
/* USER CODE BEGIN 2 */
UART1_print("\r\n\r\n");
UART1_print("program is ready and running");
UART1_print("\r\n");
ledInit(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
comInit(&huart1);//-----------这里初始化
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1) {
ledToggle();
comPrintManage();//----------这里是主函数调用
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART1) {
comCallback();
}
}
标签:CODE,huart,UART,stm32,comPrint,USER,串口,xshell
From: https://www.cnblogs.com/yswnotes/p/18197612