课前准备
#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️⃣不同进制数据算数运算很奇怪,难以理解 2️⃣ 这个场景下0x00 2位够用
- 内存映射I/O(Memory-Mapped I/O,MMIO)操作的是 I/O设备的硬件寄存器,看着是内存而已
- 这种外设一般都需要一个基地址,访问不同的寄存器,在这个基地址上加加的。
- 外设的同一个寄存器,可能有多个功能,一会这个场景,一会另一个场景,有个开关就可以控制了
uart 使用规范
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。