源代码:https://github.com/jimingkang/STM32L476_BSP
在本地电脑C:\Users\jmmy\Downloads\raspi_STM\STM32L476G_STLink_UART_Debug\STM32L476G_STLink_UART_Debug
这里采用裸机程序,没有借用库
1.)main.czjie直接初始化,然后调用(UART2_Init,USART_Write都在UART.c中)
UART2_Init(); //硬件初始化
n = sprintf((char *)buffer, "hello kaka \r\n");
USART_Write(USART2, buffer, n);
2.)UART.c
#include "UART.h"
// UART Ports:
// ===================================================
// PA.0 = UART4_TX (AF8) | PA.1 = UART4_RX (AF8)
// PB.6 = USART1_TX (AF7) | PB.7 = USART1_RX (AF7)
// PD.5 = USART2_TX (AF7) | PD.6 = USART2_RX (AF7) //这里是GPIO D ,可见虚拟串口通过GPOID67转化为USB接口信号然后连接电脑;而不是常见接到GPIOB 9,10,通过GPIOB 9,10连接硬件串口rx,tx线路(注意GPIO只是通用信号,只是负责把cpu线路导出来,具体取决于芯片设计者把他当什么用处,这里把它当串口,它就把串口信号导出连接到tx,rx,至于外部串口电路,那就不管,由更外面的电路板开发人员来负责设计rx,tx的外部连接,比如中国的电路板小公司)
void UART2_Init(void) {
// Enable the clock of USART 1 & 2
RCC->APB1ENR1 |= RCC_APB1ENR1_USART2EN; // Enable USART 2 clock
// Select the USART1 clock source
// 00: PCLK selected as USART2 clock
// 01: System clock (SYSCLK) selected as USART2 clock
// 10: HSI16 clock selected as USART2 clock
// 11: LSE clock selected as USART2 clock
RCC->CCIPR &= ~RCC_CCIPR_USART2SEL;
RCC->CCIPR |= RCC_CCIPR_USART2SEL_0;
UART2_GPIO_Init();//由前面的红色部分,可见要配置GPIO
USART_Init(USART2);//真正的uart硬件配置
//这里没用到中断接收发送,直接阻塞式
//NVIC_SetPriority(USART2_IRQn, 0); // Set Priority to 1
//NVIC_EnableIRQ(USART2_IRQn); // Enable interrupt of USART1 peripheral
}
void UART2_GPIO_Init(void) {
// Enable the peripheral clock of GPIO Port
RCC->AHB2ENR |= RCC_AHB2ENR_GPIODEN;
// ********************** USART 2 ***************************
// PD5 = USART2_TX (AF7)
// PD6 = USART2_RX (AF7)
// Alternate function, High Speed, Push pull, Pull up
// **********************************************************
// Input(00), Output(01), AlterFunc(10), Analog(11)
GPIOD->MODER &= ~(0xF << (2*5)); // Clear bits
GPIOD->MODER |= 0xA << (2*5);
GPIOD->AFR[0] |= 0x77<< (4*5);
// GPIO Speed: Low speed (00), Medium speed (01), Fast speed (10), High speed (11)
GPIOD->OSPEEDR |= 0xF<<(2*5);
// GPIO Push-Pull: No pull-up, pull-down (00), Pull-up (01), Pull-down (10), Reserved (11)
GPIOD->PUPDR &= ~(0xF<<(2*5));
GPIOD->PUPDR |= 0x5<<(2*5);
// GPIO Output Type: Output push-pull (0, reset), Output open drain (1)
GPIOD->OTYPER &= ~(0x3<<5) ;
}
//真正的uart硬件配置
void USART_Init (USART_TypeDef * USARTx) {
// Default setting:
// No hardware flow control, 8 data bits, no parity, 1 start bit and 1 stop bit
USARTx->CR1 &= ~USART_CR1_UE; // Disable USART
// Configure word length to 8 bit
USARTx->CR1 &= ~USART_CR1_M; // M: 00 = 8 data bits, 01 = 9 data bits, 10 = 7 data bits
// Configure oversampling mode: Oversampling by 16
USARTx->CR1 &= ~USART_CR1_OVER8; // 0 = oversampling by 16, 1 = oversampling by 8
// Configure stop bits to 1 stop bit
// 00: 1 Stop bit; 01: 0.5 Stop bit
// 10: 2 Stop bits; 11: 1.5 Stop bit
USARTx->CR2 &= ~USART_CR2_STOP;
// CSet Baudrate to 9600 using APB frequency (80,000,000 Hz)
// If oversampling by 16, Tx/Rx baud = f_CK / USARTDIV,
// If oversampling by 8, Tx/Rx baud = 2*f_CK / USARTDIV
// When OVER8 = 0, BRR = USARTDIV
// USARTDIV = 80MHz/9600 = 8333 = 0x208D
USARTx->BRR = 0x208D; // Limited to 16 bits
USARTx->CR1 |= (USART_CR1_RE | USART_CR1_TE); // Transmitter and Receiver enable
if (USARTx == UART4){
USARTx->CR1 |= USART_CR1_RXNEIE; // Received Data Ready to be Read Interrupt
USARTx->CR1 &= ~USART_CR1_TCIE; // Transmission Complete Interrupt
USARTx->CR1 &= ~USART_CR1_IDLEIE; // Idle Line Detected Interrupt
USARTx->CR1 &= ~USART_CR1_TXEIE; // Transmit Data Register Empty Interrupt
USARTx->CR1 &= ~USART_CR1_PEIE; // Parity Error Interrupt
USARTx->CR1 &= ~USART_CR2_LBDIE; // LIN Break Detection Interrupt Enable
USARTx->CR1 &= ~USART_CR3_EIE; // Error Interrupt Enable (Frame error, noise error, overrun error)
//USARTx->CR3 &= ~USART_CR3_CTSIE; // CTS Interrupt
}
if (USARTx == USART2){
USARTx->ICR |= USART_ICR_TCCF;
USART1->CR3 |= USART_CR3_DMAT | USART_CR3_DMAR;
}
USARTx->CR1 |= USART_CR1_UE; // USART enable
while ( (USARTx->ISR & USART_ISR_TEACK) == 0); // Verify that the USART is ready for reception
while ( (USARTx->ISR & USART_ISR_REACK) == 0); // Verify that the USART is ready for transmission
}
uint8_t USART_Read (USART_TypeDef * USARTx) {
// SR_RXNE (Read data register not empty) bit is set by hardware
while (!(USARTx->ISR & USART_ISR_RXNE)); // Wait until RXNE (RX not empty) bit is set
// USART resets the RXNE flag automatically after reading DR
return ((uint8_t)(USARTx->RDR & 0xFF));
// Reading USART_DR automatically clears the RXNE flag
}
void USART_Write(USART_TypeDef * USARTx, uint8_t *buffer, uint32_t nBytes) {
int i;
// TXE is cleared by a write to the USART_DR register.
// TXE is set by hardware when the content of the TDR
// register has been transferred into the shift register.
for (i = 0; i < nBytes; i++) {
while (!(USARTx->ISR & USART_ISR_TXE)); // wait until TXE (TX empty) bit is set
// Writing USART_DR automatically clears the TXE flag
USARTx->TDR = buffer[i] & 0xFF;
USART_Delay(300);
}
while (!(USARTx->ISR & USART_ISR_TC)); // wait until TC bit is set
USARTx->ISR &= ~USART_ISR_TC;
}
void USART_Delay(uint32_t us) {
uint32_t time = 100*us/7;
while(--time);
}
void USART_IRQHandler(USART_TypeDef * USARTx, uint8_t *buffer, uint32_t * pRx_counter){
if(USARTx->ISR & USART_ISR_RXNE) { // Received data
buffer[*pRx_counter] = USARTx->RDR; // Reading USART_DR automatically clears the RXNE flag
(*pRx_counter)++;
if((*pRx_counter) >= BufferSize ) {
(*pRx_counter) = 0;
}
} else if(USARTx->ISR & USART_ISR_TXE) {
//USARTx->ISR &= ~USART_ISR_TXE; // clear interrupt
//Tx1_Counter++;
} else if(USARTx->ISR & USART_ISR_ORE) { // Overrun Error
while(1);
} else if(USARTx->ISR & USART_ISR_PE) { // Parity Error
while(1);
} else if(USARTx->ISR & USART_ISR_PE) { // USART_ISR_FE
while(1);
} else if (USARTx->ISR & USART_ISR_NE){ // Noise Error Flag
while(1);
}
}