打印
[APM32E0]

APM32E030串口中断与shell命令

[复制链接]
147|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 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_t  UART1_RxBuff[UART1_RX_SIZE];                //串口接收缓冲区
uint8_t  UART1_TxBuff[UART1_TX_SIZE];                //串口发送缓冲区

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命令行移植完成。



nr_micro_shell-master.zip

716.43 KB

5-1 APM32E030-串口.zip

173.05 KB

5-2 APM32E030-串口-中断发送.zip

177.14 KB

5-3 APM32E030-串口-shell命令.zip

194.92 KB

使用特权

评论回复
沙发
星云狂想曲| | 2025-7-14 18:50 | 只看该作者
楼主这个态度真好!
在分享知识之后还附带把实现工程提供了。
赞一下

使用特权

评论回复
板凳
夜幕叙事曲| | 2025-7-15 21:07 | 只看该作者
这个shell小库对于串口接收的方式没有对MCU的特点进行针对性的处理。
感觉仍然停留在51单片机的处理方式呢!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

16

主题

18

帖子

0

粉丝