前言

通过xshell对stm32f103c8t6芯片进行串口调试。

最近发现xshell也可以进行串口调试,但是在数据的输入上会有一些问题。
因为正常的串口调试助手都是统一输入,直接发送,但是xshell不同,正常情况下是字符逐一输入的。
所以在进行串口调试时,需要逐个字符分析计算,最后统一处理。

用xshell调试的优点就是软件优化好,使用起来很舒服。
缺点是,没法看16进制数据;不能自定义数据帧格式;也没有输入框,也显示不了用户输入数据。

整体来说,xshell用于这种串口调试,其实不是很明智的选择。

设计

思路

初始化

主函数处理

回调函数处理

初始化之后,回调函数接收用户输入,主函数处理用户输入的数据

同时,因为xshell不能显示用户的输入数据,所以需要在主函数中打印用户输入。
不建议在回调函数中打印,具体原因代码中会有表示。

分析

本来想做成一个类,这样所有的串口都可以同时使用,但是有一说一,C语言实现类确实有点麻烦。
可以用一个结构体保存参数,然后传递到函数中,这个方法要比类简单的多,而且也能实现所有串口都可以使用的功能。但是目前一个串口就够用,就没有实现了,有兴趣的可以自己实现一下。

初始化部分

初始化部分决定了整段代码的相对独立性,所以在初始化时应该输入一个参数,让这个库可以用于任何一个串口。

这个参数应该是串口的决定性参数,如&huart1这样的。

回调函数

回调函数应该做最少的处理,毕竟中断里面做大量计算,太占资源了。

主函数处理

这一部分可以做大量的计算和处理,毕竟主函数可以被打断,不会太耗费资源。

实现

实现这些功能,要解决几个问题

  1. 输入的命令需要存储下来,方便后面处理。
  2. 回调函数是运行在中断中,可以做到即时,但是主函数是在while中,不能做到即时相应。
  3. 需要一个特定的按键来出发判断机制,做对应的命令处理。

特定命令判断

先从最简单的开始,以使用者的习惯来说,回车做为确定符号是很自然的。
退格作为命令输入之后的取消,也是相对合理的。只是在做的时候和正常的取消有点不同。

输入命令的保存

保存采用的是栈的方式,定义一个数组,再定义一个坐标指针,通过坐标指针向数组写入数据。

不同步问题

数据无法完全实时同步,所以就需要一个输出指针。这样虽然输出和输入数据还是不同步,但可以做到延迟响应,不会让数据在输出时丢失。

代码

源码

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();
	}
}

作者:一叁伍

物联沃分享整理
物联沃-IOTWORD物联网 » stm32配合xshell串口输入

发表回复