LIZARD925 发表于 2025-7-12 00:52

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]
查看完整版本: APM32E030串口中断与shell命令