ARM⑤——串行通信

一、设备间通信实现

alt

  • 传输流程

    起始位——>数据位——>校验位——>停止位 , 发送完成——>空闲状态

  • 传输速率——波特率一致

二、UART串口通信

1、串口核心器件

  • 发送器(TX):负责将 CPU 输出的并行数据(如 8 位二进制数)转换成串行数据(逐位传输),并添加通信协议所需的 “起始位、停止位、校验位”。
  • 接收器(RX):负责从外部接收串行数据,逐位解析后转换成并行数据,同时校验数据正确性(如校验位、停止位检测)。
  • 波特率发生器:生成稳定的时钟信号,用于同步发送 / 接收的 “位传输速度”(即波特率,需与通信对方一致)。

2、通信协议规定

UART 是 “异步通信”,无时钟线同步,因此通信双方必须预先约定 4 个核心参数,否则数据会解析错误:

  1. 波特率:每秒传输的 “比特数”(如 9600bps、115200bps),决定数据传输速度,双方波特率需完全一致(波特率发生器需生成对应时钟)。
  2. 数据位:每帧数据中 “有效数据的位数”(常用 8 位,少数场景用 5/6/7/9 位),如 8 位时,每次传输 1 个字节的有效数据。
  3. 停止位:每帧数据末尾的 “结束标志”,用于告知接收器 “当前帧已结束”,可配置为 1 位、1.5 位或 2 位(常用 1 位)。
  4. 校验位(可选):用于检测数据传输错误,分为奇校验(数据位 + 校验位的 “1” 的总数为奇数)、偶校验(总数为偶数)、无校验(不添加校验位),双方校验规则需一致。

3、ARM内的具体使用流程

  1. 外设原理图查找

    UART——>CON7——>BUF_XuTXD2——>XuTXD2/UART_AUDIO_TXD 发送端

    ​ ——>BUF_XuRXD2——>XuRXD2/UART_AUDIO_RXD 接收端

  2. 核心原理图查找

    XuTXD2/UART_AUDIO_TXD——> XuTXD2 / UART_AUDIO_TXD/GPA1_1 发送

    XuTXD2/UART_AUDIO_RXT——> XuTXD2 / UART_AUDIO_TXD/GPA1_0 接收

  3. 芯片手册

    使能

    寄存器 地址 Bit 备注
    GPA1CON 0x11400020 [7:4] 0x2 = UART_2_TXD 使能串口2输出
    [3:0] 0x2 = UART_2_RXD 使能串口2接收

    设置

    寄存器 地址 bit 备注
    ULCON2 0x13820000 [1:0] 11 传输位=8位
    [2] 0 1位终止位
    [5,3] 000 无校验
    [6] 0 普通模式
    UCON2 0x13820004 [3:2] 01 传输模式:中断、轮询
    [1:0] 01 接收模式:中断、轮询
    UTRSTATn 0x13820010 [1] 1 or 0 写缓存可用时 该bit位为1
    [0] 1 or 0 读缓存就绪,该bit为1

    分频计算及初始化

alt

alt

For example, if the Baud rate is 115200 bps and SCLK_UART is 100 MHz, UBRDIVn and UFRACVALn are: 
DIV_VAL = (100000000/(115200  16))–1 = 54.25 – 1    = 53.25 
UBRDIVn = 53 (integer part of DIV_VAL) 
UFRACVALn/16 = 0.25 = 4/16 
Therefore, UFRACVALn = 4

当波特率为115200的时候,串口时钟频率为100MHz ,UBRDIVn 和 UFRACVALn寄存器的公式如上计算。

UBRDIVn ——整数部分

UFRACVALn——小数部分

  1. 代码部分
#define GPA1CON (*(volatile unsigned int *)0x11000020)
#define ULCON2 (*(volatile unsigned int *)0x13820000)
#define UCON2 (*(volatile unsigned int *)0x13820004)
#define UBRDIV2 (*(volatile unsigned int *)0x13820028)
#define UFRACVAL2 (*(volatile unsigned int *)0x1382002C)
#define UTXH2 (*(volatile unsigned int *)0x13820020)
#define URXH2 (*(volatile unsigned int *)0x13820024)
#define UTRSTAT2 (*(volatile unsigned int *)0x13820010)



//延时函数
void delay(int n)
{
    volatile int cnt = 0;
    while(n--)
    {
        for(cnt ; cnt < 1024 ; cnt++)
        {}
    }

}


void int_to_string(int num, char *str) {
    int i = 0;          // 字符串索引
    int is_negative = 0; // 标记是否为负数
    unsigned int n;      // 用无符号数处理绝对值(避免-2147483648溢出)

    // 处理负数
    if (num < 0) {
        is_negative = 1;
        n = (unsigned int)(-num);  // 转为无符号数避免溢出
    } else {
        n = (unsigned int)num;
    }

    // 特殊情况:数字为0
    if (n == 0) {
        str[i++] = '0';
    } else {
        // 提取每一位数字(逆序存储)——原本就是while循环,无需修改
        while (n > 0) {
            str[i++] = (n % 10) + '0';  // 数字转ASCII字符
            n /= 10;
        }
    }

    // 添加负号(若为负数)
    if (is_negative) {
        str[i++] = '-';
    }

    // 反转字符串(用while循环替代for循环)
    int j = 0;                  // 初始化左指针
    int half_len = i / 2;       // 计算需要交换的次数
    while (j < half_len) {
        // 交换对称位置的字符
        char temp = str[j];
        str[j] = str[i - 1 - j];
        str[i - 1 - j] = temp;
        j++;  // 移动左指针
    }

    str[i] = '\0';  // 添加字符串终止符
}



//初始化 串口2
void uart_init()
{
    //GPA1使能 UART_2_TX
    GPA1CON = (GPA1CON & (~(0xff << 8))) | (0x22 << 8);
    //ULCON2 数据位 = 8  stop = 0 , 无校验 普通模式
    ULCON2 = (ULCON2 & (~(0x7f << 0))) | (0x3 << 0);
    //UCON2
    UCON2 = (UCON2 & (~(0xf << 0))) | (0x5 << 0);
    //UBRDIV2 分频  这里直接等于是因为其余位都是保留
    UBRDIV2 = 53;
    UFRACVAL2 = 4;

}


//发送单字节数据
void uart_sendChar(char ch)
{
    //判断数据发送 buffer是否为空
    while((UTRSTAT2 & (0x2)) == 0);
    UTXH2 = ch;

}

//发送字符串
void uart_sendStr(char *str)
{
    while(*str != '\0')
    {
        uart_sendChar(*str);
        str++;
    }
}

void uart_sendInteger(int num)
{
    //缓冲区
    char buf[13] = {0};
    int_to_string(num,buf);
    uart_sendStr(buf);
    
}

//接收字符
char uart_getChar()
{
    while((UTRSTAT2 & (0x1)) == 0);
    return (URXH2 & 0xff);
}

void main()
{ 
    char *str = "hello world!";
    int num = 5000;
    uart_init();
    uart_sendStr(str);
    //delay(1024);
    uart_sendInteger(num);
    while(1)
    { 
    }
}