APM32E030串口中断与shell命令
本帖最后由 LIZARD925 于 2025-7-12 22:03 编辑#技术资源##申请原创#
APM32E030系列使用记录--串口的使用与命令行的移植
[*]串口发送+接收中断
目标:实现阻塞式发送+中断接收
程序中使用串口1,配置串口为8位数据位、1位停止位、无奇偶校验,波特率115200,都为通用的串口配置,初始化程序如下
void Serial_Init(void)
{
GPIO_Config_T GPIO_InitStructure;
USART_Config_T USART_InitStructure;
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_USART1);
GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_9, GPIO_AF_PIN1);
GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_10, GPIO_AF_PIN1);
GPIO_InitStructure.mode = GPIO_MODE_AF; // 复用模式
GPIO_InitStructure.pin = GPIO_PIN_9;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.pupd = GPIO_PUPD_PU; //上拉输入
GPIO_InitStructure.outtype = GPIO_OUT_TYPE_PP; //推挽输出
GPIO_Config(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.pin= GPIO_PIN_10;
GPIO_Config(GPIOA, &GPIO_InitStructure);
USART_InitStructure.baudRate = 115200;
USART_InitStructure.hardwareFlowCtrl = USART_FLOW_CTRL_NONE;
USART_InitStructure.mode = USART_MODE_TX_RX;
USART_InitStructure.parity = USART_PARITY_NONE; //无奇偶校验
USART_InitStructure.stopBits = USART_STOP_BIT_1;
USART_InitStructure.wordLength = USART_WORD_LEN_8B;
USART_Config(USART1, &USART_InitStructure);
USART_EnableInterrupt(USART1, USART_INT_RXBNEIE);
NVIC_EnableIRQRequest(USART1_IRQn, 2);
USART_Enable(USART1);
}发送函数使用阻塞发送,等待发送结束,并重映射printf函数,如下:
void Serial_SendByte(uint8_t Byte)
{
USART_TxData(USART1, Byte);
while (USART_ReadStatusFlag(USART1, USART_FLAG_TXBE) == RESET);
}使用时需要打开
否则串口发送不成功。
中断接收函数如下,实现接收到数据后,原封不动的返回数据:void USART1_IRQHandler(void)
{
uint8_t dat;
if (USART_ReadStatusFlag(USART1, USART_FLAG_RXBNE) == SET)
{
dat = (uint8_t)USART_RxData(USART1);
printf("%c", dat);
}
}现象:串口发送的字符芯片会原封不动的返回
[*]串口中断发送+接收中断
目标:实现中断发送+中断接收
程序中使用串口1,配置串口为8位数据位、1位停止位、无奇偶校验,波特率115200,都为通用的串口配置,初始化程序如下#define TINY_COM1 USART1
#define TINY_COM1_CLK RCM_APB2_PERIPH_USART1
#define TINY_COM1_TX_PIN GPIO_PIN_9
#define TINY_COM1_TX_GPIO_PORT GPIOA
#define TINY_COM1_TX_GPIO_CLK RCM_AHB_PERIPH_GPIOA
#define TINY_COM1_TX_SOURCE GPIO_PIN_SOURCE_9
#define TINY_COM1_TX_AF GPIO_AF_PIN1
#define TINY_COM1_RX_PIN GPIO_PIN_10
#define TINY_COM1_RX_GPIO_PORT GPIOA
#define TINY_COM1_RX_GPIO_CLK RCM_AHB_PERIPH_GPIOA
#define TINY_COM1_RX_SOURCE GPIO_PIN_SOURCE_10
#define TINY_COM1_RX_AF GPIO_AF_PIN1
#define TINY_COM1_IRQn USART1_IRQn
void Serial_Init(uint32_t baud)
{
GPIO_Config_T GPIO_InitStructure;
USART_Config_T USART_InitStructure;
RCM_EnableAHBPeriphClock(TINY_COM1_TX_GPIO_CLK|TINY_COM1_RX_GPIO_CLK);
RCM_EnableAPB2PeriphClock(TINY_COM1_CLK);
GPIO_ConfigPinAF(TINY_COM1_TX_GPIO_PORT, TINY_COM1_TX_SOURCE, TINY_COM1_TX_AF);
GPIO_ConfigPinAF(TINY_COM1_RX_GPIO_PORT, TINY_COM1_RX_SOURCE, TINY_COM1_RX_AF);
GPIO_InitStructure.mode = GPIO_MODE_AF; // 复用模式
GPIO_InitStructure.pin = TINY_COM1_TX_PIN;
GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
GPIO_InitStructure.pupd = GPIO_PUPD_PU; //上拉输入
GPIO_InitStructure.outtype = GPIO_OUT_TYPE_PP; //推挽输出
GPIO_Config(TINY_COM1_TX_GPIO_PORT,&GPIO_InitStructure);
GPIO_InitStructure.pin= TINY_COM1_RX_PIN;
GPIO_Config(TINY_COM1_RX_GPIO_PORT, &GPIO_InitStructure);
USART_InitStructure.baudRate = 115200;
USART_InitStructure.hardwareFlowCtrl = USART_FLOW_CTRL_NONE;
USART_InitStructure.mode = USART_MODE_TX_RX;
USART_InitStructure.parity = USART_PARITY_NONE; //无奇偶校验
USART_InitStructure.stopBits = USART_STOP_BIT_1;
USART_InitStructure.wordLength = USART_WORD_LEN_8B;
USART_Config(TINY_COM1, &USART_InitStructure);
USART_EnableInterrupt(TINY_COM1, USART_INT_RXBNEIE);
USART_DisableInterrupt(TINY_COM1, USART_INT_TXBEIE); //失能中断发送
NVIC_EnableIRQRequest(TINY_COM1_IRQn, 2);
USART_Enable(TINY_COM1);
ring_buf_init(&Tbsend, UART1_TxBuff, sizeof(UART1_TxBuff)); /*初始化环形缓冲发送区*/
ring_buf_init(&Rbrecv, UART1_RxBuff, sizeof(UART1_RxBuff)); /*初始化环形缓冲接收区*/
}此程序只在第一个的基础上,增加了环形缓冲队列的初始化和失能中断发送,环形缓冲队列有两个,一个为接收一个为发送
#define UART1_RX_SIZE 512 //接收缓冲区长度
#define UART1_TX_SIZE 512 //发送缓冲区长度
uint8_tUART1_RxBuff; //串口接收缓冲区
uint8_tUART1_TxBuff; //串口发送缓冲区
static ring_buf_t Tbsend, Rbrecv; /*收发缓冲区管理*/我们将接收缓冲队列发到中断接收中,进行数据的接收,这样收到的数据将会存在接收队列中,如果在存满前,不将数据取出来,在满了后,新数据将无法存进去
if (USART_ReadStatusFlag(TINY_COM1, USART_FLAG_RXBNE) == SET)
{
uint8_t dat;
dat = (uint8_t)USART_RxData(TINY_COM1);
ring_buf_put(&Rbrecv, &dat, 1); /*将数据放入接收缓冲区*/
}对于发送中断,单个数据发送我们修改 Serial_SendByte 函数,将数据放入发送缓冲区,并启动中断发送
void Serial_SendByte(uint8_t Byte)
{
ring_buf_put(&Tbsend, (unsigned char *)&Byte, 1);
USART_EnableInterrupt(TINY_COM1, USART_INT_TXBEIE); //中断发送
}多数据发送我们修改 Serial_SendArray函数,并在串口中断中添加如下程序,进行串口的数据发送,当得到数据长度为0时,关闭发送中断
unsigned int Serial_SendArray(uint8_t *Array, uint16_t Length)
{
unsigned int ret;
ret = ring_buf_put(&Tbsend, (unsigned char *)Array, Length);
USART_EnableInterrupt(TINY_COM1, USART_INT_TXBEIE); //中断发送
return ret; //返回实际放入的数据长度
} if (USART_ReadStatusFlag(TINY_COM1, USART_FLAG_TXBE) == SET)//发送
{
unsigned char send_data;
USART_ClearStatusFlag(TINY_COM1, USART_FLAG_TXC);
if (ring_buf_get(&Tbsend, &send_data, 1)) /*从缓冲区中取出数据-返回数据的长度---*/
{
USART_TxData(TINY_COM1, send_data);
}
else
{
USART_DisableInterrupt(TINY_COM1, USART_INT_TXBEIE); //中断发送
}
} 此时我们的中断发送+接收基本完成,将接收到的数据再次通过串口发送出去
void rx_test(void) //放到主循环,如果接受到数据,将数据发出去
{
unsigned char rx_data;
if (ring_buf_get(&Rbrecv, &rx_data, 1))
{
USART_TxData(TINY_COM1, rx_data);
}
}主函数
int main (void)
{
LED_init();
Serial_Init(115200);
Serial_SendByte(0x01);
Serial_SendString("Hello !\r\n");
Serial_SendNumber(123,3);
printf("APM32E030\r\n");
Serial_SendArray("123",3);
while(1)
{
printf("测试\r\n");
LED1_turn();
Delay_ms(1000);
rx_test();
}
}现象:串口每一秒发送数据给串口助手,并将串口助手发送的数据原封不动的发送回去
[*]nr_micro_shell 移植
下载nr_micro_shell 源码,地址为:
https://gitee.com/nrush/nr_micro_shell复制串口中断接收和发送的工程,将inc与src文件夹添加到自己的文件中,并添加到工程中
修改nr_micro_shell_config.h 中的部分参数,将打印函数重定向,并在 static_cmd 中添加自己的命令,将shell的处理函数放入此函数中进行解析
主函数中初始化shell命令与串口;
#include "apm32e030.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "key.h"
#include "serial.h"
#include "nr_micro_shell.h"
int main (void)
{
LED_init();
Serial_Init(115200);
/* 初始化 */
shell_init();
while(1)
{
rx_test();
}
}此时我们下载后,打开串口可看到如下所示界面:
此时可输入ls -h 命令进行测试,根据命令提示进行使用
到此,串口的中断发送与shell命令行移植完成。
页:
[1]