富芮坤FR800X系列之串口整帧数据收发

FR800X系列用户启用串口收发


1、串口收发展示

串口收发

2、概要

富笍坤FR800X系列软件开发,基于官方SDK中实现串口发送和接收数据,经调试SDK发现,代码中log_init()函数已经打开串口打印消息,用户可以直接用co_printf()打印消息,这样即实现TX发送数据的环节。用户若需要串口接收数,实现上位机与机器数据交互环节,用户就需要打开串口接收。
在这里插入图片描述
本文主要讲述:用户如何打开串口接收、串口调试细节和常用接收一帧数据的方法。用户最常见得数据交互为一发一收方式,发送一帧数据,然后还回一帧数据。

3、如何启用串口接收

一般需要对串口初始化和设计串口接收中断函数
串口初始化:包括打开UART0时钟、设置Tx和Rx端口、设置波特率、使能接收中断、
代码如下(示例):

    __SYSTEM_UART0_CLK_ENABLE();
    system_set_port_pull(GPIO_PA0, GPIO_PULL_UP, true);
    system_set_port_mux(GPIO_PORT_A, GPIO_BIT_0, PORTA0_FUNC_UART0_RXD);
    system_set_port_mux(GPIO_PORT_A, GPIO_BIT_1, PORTA1_FUNC_UART0_TXD);
    pmu_set_pin_to_CPU(GPIO_PORT_A, (1<<GPIO_BIT_1));
    uart_init(UART0, 1152);
    fr_uart_enableIrq(UART0, Uart_irq_erbfi);
    NVIC_EnableIRQ(UART0_IRQn);

设计中断函数:串口接收中断函数,搜索一下uart0_isr出现的地方,在drvier_uart.c中写串口中断函数接口。

// 设计串口接收结构体
#define uartRxBufferMAX 256
typedef struct{
	uint16_t size;
	uint8_t txBuf[uartRxBufferMAX];
}st_uartBuffer_t;

// 定义一个接收数据变量
st_uartBuffer_t stRxUartBuf = {0};

// 接收中断处理函数 
void uart0_IRQHandler(void)
{
    uint8_t data;
    switch (__UART_INT_GET_ID(Uart0))
    {
        case INT_INDEX_TXE:
        {
            /* Tx empty interrupt and fifo disable */
            Uart0->IER_DLH.IER.PTIME = 0;
            Uart0->IER_DLH.IER.ETBEI = 0;
            //co_printf("---->INT_INDEX_TXE\r\n");
        }
        break;

        case INT_INDEX_RX:
        case INT_INDEX_RX_TOUT:
        {
            /* Rx ready */
            //rx fifo at least have one data

            while (Uart0->LSR.LSR_BIT.DR)
            {
                data = Uart0->DATA_DLL.DATA;
        		//uart_putc_noint_no_wait(UART0, data);
        		stRxUartBuf.txBuf[stRxUartBuf.size] = data; // 写入缓存
        		stRxUartBuf.size ++;
        		if (stRxUartBuf.size >= uartRxBufferMAX)
        		{
        			stRxUartBuf.size = 0;
                }
                //uart_putc_noint(UART0,data);  // 发送接收的数据
            }
            App_uartTimeoutTaskStart();
            /*
            while (Uart0->LSR.LSR_BIT.DR)
            {
                data = Uart0->DATA_DLL.DATA;
                uart_putc_noint(UART0,data);
            }
            */
        }
        break;

        case INT_INDEX_LINE:
        {
            volatile uint32_t line_status = Uart0->LSR.LSR_DWORD;
            //co_printf("---->INT_INDEX_LINE [%x]\r\n",line_status);
        }break;

        default:
            break;
    }
}

__attribute__((section("ram_code"))) void uart0_isr(void)
{
    uart0_IRQHandler();
}

__attribute__((section("ram_code"))) void uart1_isr(void)
{
    uart1_IRQHandler();
}

4、串口调试细节

  1. 串口接收需保证BLE处于正常工作模式,禁止进入睡眠。
  2. 在初始化增加system_sleep_disable();确保不进入睡眠。
  3. 配置IO管脚与连接的管脚要正确。

5、常用收发一帧数据

如果判定一帧数据?
串口接收一帧数据每一个字节都是连续的,一般字节与字节之间的间隔不到1mS,这样我们将间隔超过20mS的认为是一帧数据发送完成。使用软件定时器等待接收下一个字节未超过20mS的存储在接收缓存里面,超过20mS表示接收一帧数据。而 发送一帧数据:uart_send_len() 可以发送一帧长度的数据

/*
 * 功能: handle_UartRxHandle
 *
 * 注解: 串口接收一帧数据处理
 *
 * 输入: dat:缓存  len:长度
 * 输出: 无
 *
 */
static void handle_UartRxHandle(uint8_t *dat,uint32_t len)
{
    //co_printf("len:%d\r\n",len);
    uart_send_len(dat,len);    // 发送一帧数据
    UART_to_AT_CMD(dat,len); //  AT命令开发
}

/*
 * 功能: App_uartProcess
 *
 * 注解: 串口接收一帧数据处理
 *
 * 输入: 无
 * 输出: 无
 *
 */
static void App_uartProcess(void *param)
{
    handle_UartRxHandle(stRxUartBuf.txBuf,stRxUartBuf.size);
    stRxUartBuf.size  = 0;
}

/*
 * 功能: App_uartHandlerInit
 *
 * 注解: 串口接收应用初始化
 *
 * 输入: 无
 * 输出: 无
 *
 */
static void App_uartHandlerInit(void)
{
	os_timer_init(&uart_process_timer, App_uartProcess, NULL);
}

/*
 * 功能: App_uartTimeoutTaskStart
 *
 * 注解: 开始接收并等待串行数据超时
 *
 * 输入: 无
 * 输出: 无
 *
 */
void App_uartTimeoutTaskStart(void)
{
	os_timer_start(&uart_process_timer, 20, false);	//start 10ms anti-shake timer
}

6、小结

串口收一帧数据,①需要保证系统处于正常工作模式,才能正常接收数据,②还需用到软件定时器,等待20mS未收到数据认为是接收完成。
串口收发用户经常使用,如开发AT命令、上位机交互协议和串口调试等。本文代码部分已在实际项目中验证过,直接移植代码就可以使用,作者经常用这种方法来开发串口接收,不知您还有哪种更好读串口接收数据的方法,欢迎评论,谢谢!。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
富芮坤fr8016ha是一款自带计数的跳绳,跳绳的计数、暂停、复位等功能都可以通过按键进行控制。以下是基于Arduino平台的参考代码: #include <LiquidCrystal_I2C.h> //LCD库 #define BUTTON_COUNT 4 //按键数量 #define BUTTON_PIN 2 //按键引脚 #define LED_PIN 13 //LED引脚 #define LED_ON_DURATION 100 //LED亮时长(ms) #define LCD_WIDTH 16 //LCD宽度(字符) #define LCD_HEIGHT 2 //LCD高度(行数) LiquidCrystal_I2C lcd(0x27, LCD_WIDTH, LCD_HEIGHT); //创建LCD对象 int buttonPins[BUTTON_COUNT] = {2, 3, 4, 5}; //按键引脚列表 int buttonStates[BUTTON_COUNT] = {HIGH, HIGH, HIGH, HIGH}; //按键状态列表 int lastButtonStates[BUTTON_COUNT] = {HIGH, HIGH, HIGH, HIGH}; //上次按键状态列表 int buttonClicked[BUTTON_COUNT] = {0, 0, 0, 0}; //按键单击状态列表 int ledState = LOW; //LED当前状态 unsigned long ledOnTime = 0; //LED亮起时间 int jumpCount = 0; //跳绳计数 bool jumpPaused = false; //跳绳暂停状态 void setup() { pinMode(LED_PIN, OUTPUT); //设置LED引脚为输出 lcd.init(); //初始化LCD lcd.backlight(); //打开背光 lcd.setCursor(0, 0); //设置光标位置 lcd.print("Jump Count: 0"); //显示初始计数 } void loop() { //读取按键状态 for (int i = 0; i < BUTTON_COUNT; i++) { lastButtonStates[i] = buttonStates[i]; buttonStates[i] = digitalRead(buttonPins[i]); if (buttonStates[i] == LOW && lastButtonStates[i] == HIGH) { buttonClicked[i] = 1; } else { buttonClicked[i] = 0; } } //按键单击处理 if (buttonClicked[0]) { //计数 jumpCount++; if (jumpPaused) { jumpPaused = false; } displayJumpCount(); flashLed(); } if (buttonClicked[1]) { //暂停/恢复 jumpPaused = !jumpPaused; displayJumpCount(); flashLed(); } if (buttonClicked[2]) { //复位 jumpCount = 0; jumpPaused = false; displayJumpCount(); flashLed(); } if (buttonClicked[3]) { //测试 testButton(); } //LED计时控制 if (ledState == HIGH && millis() - ledOnTime >= LED_ON_DURATION) { ledState = LOW; digitalWrite(LED_PIN, ledState); } //跳绳暂停判断 if (jumpPaused) { while (digitalRead(buttonPins[1]) == LOW) { //等待恢复按键 delay(50); } } delay(50); } void displayJumpCount() { lcd.setCursor(0, 0); //设置光标位置 lcd.print("Jump Count: "); //显示计数标题 lcd.print(jumpCount); //显示实际计数值 lcd.setCursor(0, 1); //设置光标位置 if (jumpPaused) { lcd.print("Jump Paused"); } else { lcd.print(" "); //清空暂停提示文本 } } void flashLed() { ledState = HIGH; digitalWrite(LED_PIN, ledState); ledOnTime = millis(); } void testButton() { for (int i = 0; i < BUTTON_COUNT; i++) { lcd.setCursor(0, i); lcd.print("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"); while (digitalRead(buttonPins[i]) != LOW) { delay(50); } lcd.setCursor(0, i); lcd.print(buttonPins[i]); delay(1000); } } 代码中定义了4个按键分别对应计数、暂停/恢复、复位、测试操作。其中测试操作是为了调试按键,非正式的功能。 跳绳计数直接在计数按键响应中进行,每次计数时显示计数值并闪烁LED。跳绳暂停和恢复则在暂停/恢复按键响应中进行,切换暂停状态并显示相应的文本。跳绳复位则在复位按键响应中进行,将计数清零并恢复计数。另外需要注意的是,跳绳暂停时如果用户一直按住暂停/恢复按键则应该在恢复前等待用户松开按键。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小武编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值