我正在尝试从STM32 L476RG (核心L476RG开发板)上的PS/2键盘读取扫描代码。
PS/2和USART:
我相信我可以使用STM32上的USART硬件来读取PS/2数据,如果有什么原因的话请帮我理解。从我的阅读和带有作用域的观察来看,PS/2协议在数据线上发送以下数据包格式:
每一位被捕获在一个单独的时钟信号的下降边缘,这个时钟信号高度空闲。我的键盘上的时钟位于13.1 kHz左右。
如果给3.3V的电源,这两个系统都将从键盘输出3.3V,这是一个范围跟踪鞋,当连接到STM32时,这些波形很好。
出了什么问题
基本上,当按下键时,系统不会产生中断。RXNE (接收缓冲区,而不是空标志)保持低水平,不产生中断。
下面我将详细介绍,但是如果我在"0x55“模式下使用自动波特率,则会触发中断,但这只是因为设置了自动波特率错误标志。所有其他模式都什么也不做(没有中断)。
我试过什么
我使用以下代码在USART1上初始化要从键盘读取的STM32:
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();
}
默认情况下,数据位是LSB,默认情况下捕获位于第一边缘(下降边缘),我确认此波特率/备用函数代码在9600波特的标准UART连接上工作。
我也尝试使用自动波特率检测,因为键盘的波特率似乎在一整天都在漂移(12.9-13.2 kHz),我不相信波特率是稳定的。我尝试了自动波特率和没有自动波特率,我尝试了自动波特率在所有4种模式:(开始位测量,跌落测量,0x55帧检测,0x7F帧检测)。--唯一给我任何东西的是0x7F,每当我读取0x55以外的代码时,它就抛出一个自动波特率错误(除了'+‘按下一个键),但是当我用0x55 (按’+‘键)发送一个帧时,它什么也不做。
为了防止你想知道,我在main调用了这个函数。:)
/* 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 */ }
}
}
发布于 2022-11-30 06:29:06
感谢Flexz发现了以下内容:
STM32L476缺少CR2寄存器中的同步从描述部分和SLVEN位,这两个部分都存在于STM32L4+系列中,即L476只能是USART模式下的主程序。
这意味着我不能从PS/2设备中读取数据,至少不用时钟。我可以,但是仍然异步地从RX端口读取。这意味着我不想在USARTx->CR2中启用CLKEN。
如果异步处理行,则可以使用模式00中的自动波特率来捕获数据,即使波特率漂移,就像它在此键盘上所做的那样。
最终代码:
void init_keyboard(uint32_t baud)
{
//clear_buffer();
// 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_ABREN; // Enable auto Baud Rate
USART1->CR3 |= USART_CR3_OVRDIS; // Disable overrun detection
USART1->BRR |= (SystemCoreClock / baud);
USART1->CR1 |= USART_CR1_UE;
NVIC->ISER[1] |= (1 << (USART1_IRQn & 0x1F));
// Configure AF pin10 to AF7 (USART)
GPIOA->AFR[1] |= (GPIO_AF7_USART1 << 8);
// Configure PA10 (RX) in alt. func. mode
GPIOA->MODER &= ~(GPIO_MODER_MODE10);
GPIOA->MODER |= (GPIO_MODER_MODE10_1);
// Enable Global Interrupts
__enable_irq();
}
https://stackoverflow.com/questions/74609713
复制相似问题