通信

        嵌入式系统中的通信是指的是两个或两个以上的主机之间的数据交互,主机指的是在通信中主动发起、控制整个通信过程的设备或模块,例如芯片,单片机

通信方式的三大分类标准

        1,异步或同步:通信双方如何让数据的收发节奏保持一致

                异步:不需要专门的时钟线,收发双方约定好波特率,靠起始位、停止位来识别一个字节的开始和结束。硬件简单、连线少,但是传输速率不高

                同步:有专门的时钟线,发送方驱动时钟,接收方根据时钟边沿采样数据。传输速率高、抗干扰强,但是硬件连线多

        2,串行或并行:描述数据传输的位数

                串行:数据在一条线上一位一位地依次传输。连线少、适合远距离传输,但速率相对慢

                并行:数据的多位在多条线上同时传输,一次就能发送一个完整的字节。连线多、易受干扰、不适合远距离传输,但传输数量快

        3,单工或半双工或全双工,描述数据的流向

                单工:数据只能单向传输

                半双工:数据可以双向传输,但同一时间只能有一个方向传输

                全双工:数据可以同时双向传输

串口通信

UART结构框图

部分相关寄设施

URXD接收数据寄存器

UTXD发送数据寄存器

        像31~8位后面的意思是只读位为0,表明这几位bit位不允许更改也更改不了,以下未出现的bit位均为这种情况

UCR控制寄存器

UCR1

UCR2

UCR3

        注:例子和学习仅需第二bit

UFCR:FIFO控制寄存器

USR2状态寄存器

波特率相关寄存器

UBIR波特率整数寄存器

UBMR波特率模数寄存器

波特率配置公式

        Baud Rate:最终配置的波特率

        Ref Freq:输入时钟频率

IOMUXC输入输出复用器

#include "uart.h"
#include "MCIMX6Y2.h"
#include "fsl_iomuxc.h"
#include "interrupt.h"
#include <string.h>

// 缓冲区大小定义
#define UART_RX_BUFFER_SIZE 256
#define UART_CMD_BUFFER_SIZE 128

// 环形接收缓冲区
static uint8_t rx_buffer[UART_RX_BUFFER_SIZE];
static volatile uint16_t rx_head = 0;
static volatile uint16_t rx_tail = 0;

// 命令缓冲区
static char cmd_buffer[UART_CMD_BUFFER_SIZE];
static volatile uint8_t cmd_ready = 0;
static volatile uint16_t cmd_length = 0;

// 命令回调函数指针
static uart_cmd_callback_t cmd_callback = NULL;

void uart1_init(void)
{
    // 复用控制
    IOMUXC_SetPinMux(IOMUXC_UART1_RX_DATA_UART1_RX, 0);
    IOMUXC_SetPinMux(IOMUXC_UART1_TX_DATA_UART1_TX, 0);  
    // 电气特性
    IOMUXC_SetPinConfig(IOMUXC_UART1_RX_DATA_UART1_RX, 0x10B0);
    IOMUXC_SetPinConfig(IOMUXC_UART1_TX_DATA_UART1_TX, 0x10B0);

    UART1->UCR2 &= ~(1 << 0);
    // uart配置
    unsigned int t;
    t = UART1->UCR2;
    t |= (1 << 14);
    t &= ~(1 << 8);
    t &= ~(1 << 6);
    t |= (1 << 5);
    t |= (1 << 2);
    t |= (1 << 1);

    UART1->UCR2 = t;
    UART1->UCR3 |= (1 << 2);
    UART1->UFCR &= ~(7 << 7);
    UART1->UFCR |= (5 << 7);
    // 波特率配置
    UART1->UBIR = 999;
    UART1->UBMR = 43401;
    UART1->UCR1 |= (1 << 0);    // 使能uart1
    
    // 初始化缓冲区
    rx_head = 0;
    rx_tail = 0;
    cmd_ready = 0;
    cmd_length = 0;
    cmd_callback = NULL;
}

/**
 * 注册UART中断
 */
void uart1_register_interrupt(void)
{
    // 1. 清除所有中断标志
    UART1->USR1 = 0xFFFFFFFF;
    UART1->USR2 = 0xFFFFFFFF;
    
    // 2. 使能接收中断
    UART1->UCR1 |= (1 << 9);
    
    // 3. 注册中断服务函数
    system_interrupt_register(UART1_IRQn, uart1_irq_handler);
    
    // 4. 在GIC中使能中断
    GIC_EnableIRQ(UART1_IRQn);
    GIC_SetPriority(UART1_IRQn, 0);
}

/**
 * UART中断处理函数
 */
void uart1_irq_handler(void)
{
    // 检查接收中断
    if (UART1->USR2 & (1 << 0)) {
        while ((UART1->USR2 & (1 << 0)) != 0) {
            uint8_t data = (uint8_t)UART1->URXD;
            
            // 存入环形缓冲区
            uint16_t next = (rx_head + 1) % UART_RX_BUFFER_SIZE;
            if (next != rx_tail) {
                rx_buffer[rx_head] = data;
                rx_head = next;
                
                // 构建命令字符串
                if (data == '\r' || data == '\n') {
                    if (cmd_length > 0) {
                        cmd_buffer[cmd_length] = '\0';
                        cmd_ready = 1;
                        cmd_length = 0;
                    }
                }
                // 处理退格键
                else if (data == 0x08 || data == 0x7F) {
                    if (cmd_length > 0) {
                        cmd_length--;
                    }
                }
                // 处理可打印字符
                else if (data >= 32 && data <= 126) {
                    if (cmd_length < UART_CMD_BUFFER_SIZE - 1) {
                        cmd_buffer[cmd_length++] = data;
                    }
                }
            }
        }
    }
    
    // 清除中断标志
    UART1->USR1 = 0xFFFFFFFF;
    UART1->USR2 = 0xFFFFFFFF;
}

void putc(unsigned char d)
{
    while ((UART1->USR2 & (1 << 3)) == 0);
    UART1->UTXD = d;
}

unsigned char getc(void)
{
    return 0;
}

void raise(int n)
{
    (void)n;
}

/**
 * 设置命令回调函数
 */
void uart_set_cmd_callback(uart_cmd_callback_t callback)
{
    cmd_callback = callback;
}

/**
 * 检查是否有命令就绪
 */
int uart_has_command(void)
{
    return cmd_ready;
}

/**
 * 处理接收到的命令
 */
void uart_process_commands(void)
{
    if (cmd_ready && cmd_callback != NULL) {
        cmd_callback(cmd_buffer);
        cmd_ready = 0;
    }
}

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐