#if 1
/// 重定向c庫函數printf到USART1
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (uint8_t) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}
/// 重定向c庫函數scanf到USART1
int fgetc(FILE *f)
{
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(USART1);
}
#endif
USART 隻需兩根信号線即可完成雙向通信,對硬體要求低,使得很多子產品都預留USART 接口來實作與其他子產品或者控制器進行資料傳輸,比如 GSM 子產品, WIFI 子產品、藍牙子產品
APB2(最高 90MHz) | APB1(最高 45MHz) | |||||||
USART1 | USART6 | USART2 | USART3 | UART4 | UART5 | UART7 | UART8 | |
TX | PA9/PB6 | PC6/PG14 | PA2/PD5 | PB10/PD8 /PC10 | PA0/PC10 | PC12 | PF7/PE8 | PE1 |
RX | PA10/PB7 | PC7/PG9 | PA3/PD6 | PB11/PD9 /PC11 | PA1/PC11 | PD2 | PF6/PE7 | PE0 |
SCLK | PA8 | PG7/PC8 | PA4/PD7 | PB12/PD10 /PC12 | ||||
nCTS | PA11 | PG13/PG15 | PA0/PD3 | PB13/PD11 | ||||
nRTS | PA12 | PG8/PG12 | PA1/PD4 | PB14/PD12 |
序列槽1收發資料配置
配合原子的 usmart可以友善的進行調試,使用usmart可以通過序列槽調用函數,可以傳參數非常友善。
void NVIC_Configuration_1(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 配置 NVIC 為優先級綠1 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置中斷源:按鍵 1 */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
/* 配置搶占優先級: 1 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
/* 配置子優先級_1 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
/* 使能中斷通道 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void USART1_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* config USART1 clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
/* USART1 GPIO config */
/* Configure USART1 Tx (PA.09) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART1 Rx (PA.10) as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* USART1 mode config */
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
NVIC_Configuration_1();
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, DISABLE);
(void)USART1->SR; (void)USART1->DR;
USART_ClearFlag(USART1, USART_FLAG_TC);
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
USART_Cmd(USART1, ENABLE);
}
void USART1_IRQHandler_FUN(void)
{
u8 data;
(void)USART1->SR; //Error clear;
data = (u8)(USART1->DR & (u16)0x01FF);
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
resevice_buf(data);//
get_buf_usart1[get_usart1_i] = data;
USART_SendData(USART1, data);
get_usart1_i++;
if(get_buf_usart1[0] != 0xFF)
{
get_usart1_i=0;
}
if(get_usart1_i==4)
{
AnalizingBuf2();
get_usart1_i = 0;
gRxHostBufferFlush(4,get_buf_usart1);
}
}
/// 重定向c庫函數printf到USART1
int fputc(int ch, FILE *f)
{
/* 發送一個位元組資料到USART1 */
USART_SendData(USART1, (uint8_t) ch);
/* 等待發送完毿*/
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}
/// 重定向c庫函數scanf到USART1
int fgetc(FILE *f)
{
/* 等待序列槽1輸入資料 */
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(USART1);
}
使用USART1進行序列槽調試,列印資訊到電腦
程式是如何找到中斷服務程式呢?在啟動檔案startup_stm32f10x_md.s中有這樣一段代碼,彙編DCD USART1_IRQHandler

stm32序列槽調試是一個很好的方法
一般有4個上的序列槽,可以将printf函數重定向到一個UART。這樣就可以用printf函數将單片機的資料列印到PC上的超級終端或序列槽調試助手。
可以通過序列槽發送一些參數友善調試,可以用一個協定易于操作
//定義一個協定,關于資料收發的
//第一位:判斷資料是否正确
//第二位:判斷資料是否正确
//第三位:存放參數多少
//第四位:參數[1]
//第五位:參數[2]
//第n位:參數[n]
char get_From_PC[64];
bool Buffur_Full = FALSE;//定義成全局變量
char buf[64];//定義成全局變量
int buf_conut =0
void DEBUG_USART_IRQHandler(void)
{
uint8_t ucTemp;
if (USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) {
buf[buf_conut++] = USART_ReceiveData( USART1 );
PacketCheck();
}
}
void BufferFlush(u32 BufferSize){
for(u32 counter=0; counter<BufferSize; counter++) buf[counter] = 0;
}
void PacketCheck(void)
{
int para_length = 0;
//Header Check
if(buf[0]!=0xff){ BufferFlush(buf_conut); buf_conut=0; return; }
else if(buf_conut==1) return;
if(buf[1]!=0xff){ BufferFlush(buf_conut); buf_conut=0; return; }
else if(buf_conut==2) return;
if(buf_conut>2)
{
para_length = buf[2];
if(buf_conut - 2> para_length)
{
for(int i= 0;i<para_length ;i++)
{
get_From_PC[i] = buf[i+3];
}
}
if(buf_conut == para_length +2)
{
Buffur_Full = TURE;
gRxHostBufferFlush(buf_conut);
buf_conut = 0;
}
}
}
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
工作模式配置
//USART 初始化配置
void Debug_USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_AHB1PeriphClockCmd(DEBUG_USART_RX_GPIO_CLK |
DEBUG_USART_TX_GPIO_CLK,
ENABLE);
RCC_APB2PeriphClockCmd(DEBUG_USART_CLK, ENABLE);
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_PIN ;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_PIN;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
GPIO_PinAFConfig(DEBUG_USART_RX_GPIO_PORT,
DEBUG_USART_RX_SOURCE,
DEBUG_USART_RX_AF);
GPIO_PinAFConfig(DEBUG_USART_TX_GPIO_PORT,
DEBUG_USART_TX_SOURCE,
DEBUG_USART_TX_AF);
USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(DEBUG_USART, &USART_InitStructure);
NVIC_Configuration();
USART_ITConfig(DEBUG_USART, USART_IT_RXNE, ENABLE
USART_Cmd(DEBUG_USART, ENABLE);
}
GPIO_PinAFConfig 函數接收三個參數,第一個參數為 GPIO 端口,比如 GPIOA;第二個參數是指定要複用的引腳号,比如 GPIO_PinSource10;第三個參數是選擇複用外設,比如 GPIO_AF_USART1。該函數最終操作的是 GPIO 複用功能寄存器 GPIO_AFRH 和GPIO_AFRL,分高低兩個。
字元發送
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
USART_SendData(pUSARTx,ch);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k=0;
do {
Usart_SendByte( pUSARTx, *(str + k) );
k++;
} while (*(str + k)!='\0');
while (USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET) {
}
}
Usart_SendByte 函數用來在指定 USART 發送一個 ASCLL 碼值字元,它有兩個形參,第一個為 USART,第二個為待發送的字元。它是通過調用庫函數 USART_SendData 來實作的,并且增加了等待發送完成功能。通過使用 USART_GetFlagStatus 函數來擷取 USART事件标志來實作發送完成功能等待,它接收兩個參數,一個是 USART,一個是事件标志。這裡我們循環檢測發送資料寄存器為空這個标志,當跳出 while 循環時說明發送資料寄存器為空這個事實。
Usart_SendString 函數用來發送一個字元串,它實際是調用 Usart_SendByte 函數發送每個字元,直到遇到空字元才停止發送。最後使用循環檢測發送完成的事件标志來實作保證資料發送完成後才退出函數
USART 中斷服務函數
void DEBUG_USART_IRQHandler(void)
{
uint8_t ucTemp;
if (USART_GetITStatus(DEBUG_USART,USART_IT_RXNE)!=RESET) {
ucTemp = USART_ReceiveData( DEBUG_USART );
USART_SendData(DEBUG_USART,ucTemp);
}
}
這段代碼是存放在 stm32f4xx_it.c 檔案中的,該檔案用來集中存放外設中斷服務函數。當我們使能了中斷并且中斷發生時就會執行中斷服務函數。
使能了 USART 接收中斷,當 USART 有接收到資料就會執行DEBUG_USART_IRQHandler 函數。 USART_GetITStatus 函數與 USART_GetFlagStatus 函數類似用來擷取标志位狀态,但 USART_GetITStatus 函數是專門用來擷取中斷事件标志的,并傳回該标志位狀态。使用 if 語句來判斷是否是真的産生 USART 資料接收這個中斷事件,如果是真的就使用 USART 資料讀取函數 USART_ReceiveData 讀取資料到指定存儲區。然後再調用 USART 資料發送函數 USART_SendData 把資料又發送給源裝置。