Arduino Due USART0底层寄存器配置问题:无法收发数据求助
Arduino Due USART0(RX1/TX1)底层寄存器配置收发故障排查求助
尝试通过底层寄存器配置Arduino Due的USART0(映射至RX1和TX1)实现字符收发功能,已确认硬件连接无误且能正常控制内置LED,但USART0始终无法完成收发操作。已查阅Atmel官方文档但未发现配置遗漏,恳请提供排查建议。
完整配置代码如下:
#include <stdint.h> #include "core_cm3.h" /* Base addresses for peripherals */ #define PIOA_BASE (0x400E0E00U) #define PMC_BASE (0x400E0600U) /* Peripheral instances */ #define PIOA ((PIO_TypeDef *)PIOA_BASE) #define PMC ((PMC_TypeDef *)PMC_BASE) #define ID_PIOA (11U) #define ID_USART0 (17U) void USART0_Init(uint32_t baudrate) { // Step 1: Enable the peripheral clock for USART0 PMC->PMC_WPMR = (0x504D43 << 8); PMC->PMC_PCER0 = (1 << ID_USART0); // Enable clock for USART0 // Step 2: Configure TX and RX pins (PA10 for TX, PA11 for RX, Peripheral A) PIOA->PIO_WPMR = (0x50494F << 8); // disable write protect PIOA->PIO_ABSR &= ~((1 <<10) | (1<<11)); // Select Peripheral A for USART0 PIOA->PIO_PDR |= (1 <<10) | (1<<11); // Disable GPIO control for PA10, PA11 USART0->US_WPMR = (0x555341 << 8); //disable write protect // Step 3: Disable USART0 before configuration USART0->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RXDIS | US_CR_TXDIS; // Step 4: Configure baud rate uint32_t cd = SYSTEM_CLOCK / (16 * baudrate); // CD = MCK / (16 * baudrate) USART0->US_BRGR = cd; // Step 5: Configure USART0 mode USART0->US_MR = US_MR_CHRL_8_BIT // 8-bit data | US_MR_PAR_NO // No parity | US_MR_NBSTOP_1_BIT // 1 stop bit | US_MR_CHMODE_NORMAL; // Normal mode (not loopback or test) // Step 6: Enable the receiver and transmitter USART0->US_CR = US_CR_RXEN | US_CR_TXEN; } void USART0_SendChar(char c) { // Wait for the transmitter to be ready while (!(USART0->US_CSR & US_CSR_TXRDY)); USART0->US_THR = c; // Write character to Transmit Holding Register } char USART0_ReceiveChar() { // Wait for a character to be received while (!(USART0->US_CSR & US_CSR_RXRDY)); return USART0->US_RHR; // Read character from Receive Holding Register } int main(void) { PMC->PMC_WPMR = (0x504D43 << 8); // Enable the clock for PIOA PMC->PMC_PCER0 = (1 << ID_PIOA); // Enable clock for PIOB PMC->PMC_PCER0 = (1 << ID_PIOB); /* Set FWS according to SYS_BOARD_MCKR configuration */ EFC0->EEFC_FMR = EEFC_FMR_FWS(4); EFC1->EEFC_FMR = EEFC_FMR_FWS(4); /* Initialize main oscillator */ if (!(PMC->CKGR_MOR & CKGR_MOR_MOSCSEL)) { PMC->CKGR_MOR = SYS_CKGR_MOR_KEY_VALUE | SYS_BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN; while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) { } } /* Switch to 3-20MHz Xtal oscillator */ PMC->CKGR_MOR = SYS_CKGR_MOR_KEY_VALUE | SYS_BOARD_OSCOUNT | CKGR_MOR_MOSCRCEN | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCSEL; while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) { } PMC->PMC_MCKR = (PMC->PMC_MCKR & ~(uint32_t)PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK; while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { } /* Initialize PLLA */ PMC->CKGR_PLLAR = SYS_BOARD_PLLAR; while (!(PMC->PMC_SR & PMC_SR_LOCKA)) { } /* Switch to main clock */ PMC->PMC_MCKR = (SYS_BOARD_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_MAIN_CLK; while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { } /* Switch to PLLA */ PMC->PMC_MCKR = SYS_BOARD_MCKR; while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) { } PMC->PMC_PCER0 = (1 << ID_PIOB); USART0_Init(9600); const char *message = "USART0 Initialized at 9600 baud.\r\n"; for (const char *p = message; *p; p++) { USART0_SendChar(*p); } while (1) { char received = USART0_ReceiveChar(); // Wait for a character USART0_SendChar(received); // Echo it back } return 0; }
排查建议
补充USART0基地址与结构体定义:代码中直接使用
USART0但未定义其基地址和对应结构体,编译器无法识别该外设。需添加:#define USART0_BASE (0x400E0800U) typedef struct { volatile uint32_t US_CR; // Control Register volatile uint32_t US_MR; // Mode Register volatile uint32_t US_IER; // Interrupt Enable Register volatile uint32_t US_IDR; // Interrupt Disable Register volatile uint32_t US_IMR; // Interrupt Mask Register volatile uint32_t US_CSR; // Channel Status Register volatile uint32_t US_RHR; // Receive Holding Register volatile uint32_t US_THR; // Transmit Holding Register volatile uint32_t US_BRGR; // Baud Rate Generator Register volatile uint32_t US_RTOR; // Receiver Time-out Register volatile uint32_t US_TTGR; // Transmitter Timeguard Register volatile uint32_t US_WPMR; // Write Protection Mode Register volatile uint32_t US_WPSR; // Write Protection Status Register // 其他寄存器可根据需求补充 } USART_TypeDef; #define USART0 ((USART_TypeDef *)USART0_BASE)定义SYSTEM_CLOCK宏:计算波特率时使用的
SYSTEM_CLOCK未定义,需根据实际主时钟(MCK)值设置,Arduino Due默认MCK为84MHz,添加:#define SYSTEM_CLOCK 84000000U恢复外设写保护(规范操作):配置完PIOA、USART0、PMC后,建议恢复写保护防止误操作,例如配置PIOA后添加:
PIOA->PIO_WPMR = 0; // 锁定写保护验证时钟配置正确性:确认main函数中最终MCK频率与
SYSTEM_CLOCK一致,可通过读取PMC_MCKR寄存器或示波器测量相关引脚时钟验证。添加错误状态处理:在接收函数中增加错误检查与清除逻辑,避免因溢出、帧错误等导致接收阻塞:
char USART0_ReceiveChar() { while (!(USART0->US_CSR & US_CSR_RXRDY)) { // 检查并清除错误状态 if (USART0->US_CSR & (US_CSR_OVRE | US_CSR_FRAME | US_CSR_PARE)) { USART0->US_CR = US_CR_RSTSTA; } } return USART0->US_RHR; }确认USART复位生效:在执行
US_CR_RSTRX和US_CR_RSTTX后,可短暂延时或读取状态寄存器确保复位完成,再进行后续配置。
内容的提问来源于stack exchange,提问作者Godspped
相关产品推荐
相关产品推荐

