STM32 L476RG通过USART读取PS/2键盘扫描码异常求助
在NUCLEO L476RG开发板上读取PS/2键盘扫描码的问题
PS/2与USART
我想利用STM32的USART硬件读取PS/2数据,如果这种方案不可行,请告知原因。根据资料查阅和示波器观测,PS/2协议在数据线上的数据包格式如下:
- 1个起始位,始终为0;
- 8个数据位,最低位优先;
- 1个奇校验位;
- 1个停止位,始终为1。
每个位在独立时钟信号的下降沿捕获,时钟空闲时为高电平,我的键盘时钟约为13.1kHz。给键盘供电3.3V时,双方输出均为3.3V,示波器波形显示连接STM32后正常。
问题现象
核心问题是按键时系统未产生中断,*RXNE(接收缓冲区非空标志)*始终为低,无中断触发。若使用0x55模式的自动波特率,仅会因自动波特率错误标志置位触发中断,其他模式均无任何反应。
已尝试的操作
我使用以下代码初始化STM32的USART1以读取键盘数据:
void init_keyboard(uint32_t baud) { // Enable clock to GPIOA RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN; // Enable clock to USART1 RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // Configure UART USART1->CR1 |= USART_CR1_RE | // Receiver enabled USART_CR1_PCE | // Parity control enabled USART_CR1_PS | // Odd parity USART_CR1_M0 | // 8 data bits USART_CR1_RXNEIE; // Enable RX interrupt USART1->CR1 &= ~(USART_CR1_TE); USART1->CR2 |= USART_CR2_CLKEN | // Enable USART clock (sync mode) USART_CR2_ABREN | // Enable auto Baud Rate USART_CR2_CPOL; // Clock polarit 1 (idle high) // The following need to be cleared for sync mode USART1->CR2 &= ~(USART_CR2_LINEN); USART1->CR3 &= ~(USART_CR3_SCEN | USART_CR3_HDSEL | USART_CR3_IREN); USART1->BRR |= (SystemCoreClock / baud); // set baud rate USART1->CR1 |= USART_CR1_UE; NVIC->ISER[1] |= (1 << (USART1_IRQn & 0x1F)); // Configure AF pins 8 and 10 to AF7 (USART) GPIOA->AFR[1] |= (GPIO_AF7_USART1 << 0); GPIOA->AFR[1] |= (GPIO_AF7_USART1 << 8); // Configure PA8 (CK) and PA10 (RX) in alt. func. mode GPIOA->MODER &= ~(GPIO_MODER_MODE8 | GPIO_MODER_MODE10); GPIOA->MODER |= (GPIO_MODER_MODE8_1 | GPIO_MODER_MODE10_1); // Enable Global Interrupts __enable_irq(); }
数据位默认最低位优先,默认在第一个边沿(下降沿)捕获,且已确认该波特率/复用功能码在9600波特率的标准UART连接中可行。
由于键盘波特率存在漂移(12.9-13.2kHz),我尝试启用自动波特率检测,测试了全部4种模式(起始位测量、下降沿到下降沿测量、0x55帧检测、0x7F帧检测)。仅0x7F模式有反应:读取非0x55的扫描码(按下除+外的按键)时触发自动波特率错误,但发送0x55帧(按下+键)时无任何反应。
主函数中已调用初始化函数,中断服务函数如下:
/* ISR for handling keypresses */ void USART1_IRQHandler(void); int main(void) { HAL_Init(); SystemClock_Config(); init_keyboard(13120); while (1) {/* wait for interrupts */ } } void USART1_IRQHandler(void) { if (USART1->ISR & USART_ISR_RXNE) { char read_byte = USART1->RDR; while (1) {/* catch here for debugging */ } } }
内容的提问来源于stack exchange,提问作者M Tut
相关产品推荐
相关产品推荐

