课前准备

#define UART0 0x10000000L
//用到那个寄存器的就传入那个寄存器
//每一个都是8位的地址,8位一个字节, 内存就是要按照字节寻址的
//volatile 避免编译器, 通用在做法
#define UART_REG(reg) ((volatile uint8_t *)(UART0 + reg))

//方法一: 
#define RHR 0    // Receive Holding Register (read mode)
#define THR 0    // Transmit Holding Register (write mode)
#define DLL 0    // LSB of Divisor Latch (write mode)
#define IER 1    // Interrupt Enable Register (write mode)
#define DLM 1    // MSB of Divisor Latch (write mode)
#define FCR 2    // FIFO Control Register (write mode)
#define ISR 2    // Interrupt Status Register (read mode)
#define LCR 3    // Line Control Register
#define MCR 4    // Modem Control Register
#define LSR 5    // Line Status Register
#define MSR 6    // Modem Status Register
#define SPR 7    // ScratchPad Register

//方法二 : 
#define RBR (UART_BASE_ADDR + 0x00)  // 接收缓冲寄存器
#define THR (UART_BASE_ADDR + 0x00)  // 发送保持寄存器
#define IER (UART_BASE_ADDR + 0x01)  // 中断使能寄存器
#define IIR (UART_BASE_ADDR + 0x02)  // 中断识别寄存器
#define FCR (UART_BASE_ADDR + 0x02)  // FIFO 控制寄存器
#define LCR (UART_BASE_ADDR + 0x03)  // 线路控制寄存器
#define MCR (UART_BASE_ADDR + 0x04)  // 调制解调器控制寄存器
#define LSR (UART_BASE_ADDR + 0x05)  // 线路状态寄存器
#define MSR (UART_BASE_ADDR + 0x06)  // 调制解调器状态寄存器
#define DLL (UART_BASE_ADDR + 0x00)  // 分频锁存低字节
#define DLM (UART_BASE_ADDR + 0x01)  // 分频锁存高字节

//方法三 : 
#define RBR 0x00  // 接收缓冲寄存器
#define THR 0x00  // 发送保持寄存器

//寄存器是一个地址, *地址就是读值了, 都是语意
#define uart_read_reg(reg) (*(UART_REG(reg)))
#define uart_write_reg(reg, v) (*(UART_REG(reg)) = (v))

//通用写法
void enable_receive_interrupt() {
    //第一位是1,|的话,其他的位不受影响,第一位改变
    *(volatile unsigned char *)IER |= 0x01;  
}

void disable_receive_interrupt() {
 //~的话,其他位是1,第一位是0,&的话,其他的位不受影响,第一位改变
    *(volatile unsigned char *)IER &= ~0x01; ,
}

点评:

  1. 方法三可读性更好,为啥? 1️⃣不同进制数据算数运算很奇怪,难以理解 2️⃣ 这个场景下0x00 2位够用
  2. 内存映射I/O(Memory-Mapped I/O,MMIO)操作的是 I/O设备的硬件寄存器,看着是内存而已
  3. 这种外设一般都需要一个基地址,访问不同的寄存器,在这个基地址上加加的。
  4. 外设的同一个寄存器,可能有多个功能,一会这个场景,一会另一个场景,有个开关就可以控制了

uart 使用规范

image.png


putao
5 声望0 粉丝

推动世界向前发展,改善民生。