開發平臺
- 野火F429開發板
- 標準庫
通訊基本概念
- 同步通訊和異步通訊
同步通訊和異步通訊的區別在於有沒有時鐘信號線 - 全雙工、半雙工、單工通訊
全雙工可以收發同時進行
半雙工可以收發但不可同時進行
單工只能收或發
USART
- 三大時序:USART、I2C、SPI,USART是其中之一了
- USART時序:起始位爲低電平、然後發送數據8位數據是沒有校驗位的,9位數據是有校驗位的、停止位爲高電平。時序如下圖:(字長爲8)
現在我使用串口一般都是打印調試信息或者藍牙通訊 ,只會用到TX和RX,不需要用到時鐘信號線,所以是異步半雙工
如果想要操作寄存器,那就要看功能框圖了
1.TX發送數據引腳、RX接受數據引腳,所以要把引腳配置爲串口複用引腳(每個串口對應的引腳都不一樣,這樣查看手冊)
2.發送數據寄存器和接收數據寄存器,還有發送移位寄存器和接受移位寄存器
發送數據時,發送寄存器將數據一位位的移向移位寄存器發送出去
接收數據時,將數據接收到移位寄存器然後再移向接收寄存器
3.控制寄存器CR1:要使能USART、設置數據位(字長)、是否開啓校驗位、奇校驗還是偶校驗、作爲發送器還是作爲接收器(使能)
4.波特率設置,直接操作寄存器的時候要自己算出數值,然後寫入寄存器,如果用標準庫就不需要計算了,已經算好了。公式如下:
OVER8:過採樣模式,根據選擇的模式去更改權位(計算小數的時候)
使用標準庫的話上面的瞭解一下就好了
- 串口的四個參數:波特率、數據位、校驗位、停止位。
- 波特率:每秒中傳輸了多少個碼元
- 數據位:八位或者九位,八位是沒有校驗位九位是有校驗位
- 使能了校驗位之後每個字符的數據幀格式:啓動位+數據位+校驗位+停止位
沒有使能校驗位每個字符的數據幀格式:啓動位+數據位+停止位 - 停止位:表示數據已經發送完成了,停止位長傳輸準確率高,效率低 停止位分爲0.5位、1位、1.5位、2位
0.5位和1.5位用在智能卡模式,一般情況下用1位停止位,2位停止位一般用於USART模式、單線模式、調制解調器模式。 - 一般情況:波特率:115200、數據位:8位、無校驗位、停止位:1位
要想實現通訊,發送設備和接受設備波特率、數據位、校驗位、停止位必須相同纔可實現通訊
1.初始化串口的引腳
2.配置串口的參數
3.編寫發送字符串函數
4.重定向printf函數和scanf函數
什麼是重定向?簡單來說,你喝水要喝進肚子裏,可是你喝的時候是喝進腦子裏的,你必須重定向才能讓水喝進肚子裏。
代碼如下:
#ifndef __USART__H
#define __USART__H
#include "main.h"
#define USART_TX_CLOCK RCC_AHB1Periph_GPIOA
#define USART_RX_CLOCK RCC_AHB1Periph_GPIOA
#define USART_TX_PORT GPIOA
#define USART_RX_PORT GPIOA
#define USART_TX_PINSOURCE GPIO_PinSource9
#define USART_RX_PINSOURCE GPIO_PinSource10
#define USART_AF GPIO_AF_USART1
#define USART_TX_PIN GPIO_Pin_9
#define USART_RX_PIN GPIO_Pin_10
#define USART_CLOCK_Cmd() RCC_APB2PeriphClockCmd(USART_CLOCK,ENABLE)
#define USART_CLOCK RCC_APB2Periph_USART1
#define USART USART1
#define BAUDRATE 115200
void USART_GPIO_Config(void);
void USART_Config(void);
void USATR_Sendbyte(uint16_t data);
void USART_Sendstring(char *string);
int fputc(int ch, FILE *f);
#endif
#include "usart.h"
void USART_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/*開USART引腳複用時鐘*/
RCC_AHB1PeriphClockCmd(USART_TX_CLOCK|
USART_RX_CLOCK,ENABLE);
/*
**複用模式
**不上拉不下拉
**TX->PB6 RX->PB7
*/
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Pin=USART_TX_PIN;
GPIO_Init(USART_TX_PORT,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
GPIO_InitStruct.GPIO_Pin=USART_RX_PIN;
GPIO_Init(USART_RX_PORT,&GPIO_InitStruct);
/*設置複用功能*/
GPIO_PinAFConfig(USART_TX_PORT,USART_TX_PINSOURCE,USART_AF);
GPIO_PinAFConfig(USART_RX_PORT,USART_RX_PINSOURCE,USART_AF);
}
void USART_Config(void)
{
USART_InitTypeDef USART_InitStruct;
/*引腳配置*/
USART_GPIO_Config();
/*開串口時鐘*/
USART_CLOCK_Cmd();
/*
**波特率115200
**發送和接收模式
**無校驗位
**停止位爲1
**8位數據位
**不使用硬件流
*/
USART_InitStruct.USART_BaudRate=BAUDRATE;
USART_InitStruct.USART_Parity=USART_Parity_No;
USART_InitStruct.USART_StopBits=USART_StopBits_1;
USART_InitStruct.USART_WordLength=USART_WordLength_8b;
USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;
USART_Init(USART,&USART_InitStruct);
/*使能串口*/
USART_Cmd(USART,ENABLE);
}
void USATR_Sendbyte(uint16_t data)
{
USART_SendData(USART,data);
while(USART_GetFlagStatus(USART,USART_FLAG_TXE)==RESET);
}
void USART_Sendstring(char *string)
{
unsigned int i=0;
do
{
USATR_Sendbyte(*(string+i));
i++;
} while (*(string+i)!='\0');
while(USART_GetFlagStatus(USART,USART_FLAG_TC)==RESET);
}
///重定向c庫函數printf到串口,重定向後可使用printf函數
int fputc(int data, FILE *f)
{
/* 發送一個字節數據到串口 */
USART_SendData(USART,(uint8_t) data);
/* 等待發送完畢 */
while (USART_GetFlagStatus(USART, USART_FLAG_TXE) == RESET);
return (data);
}
int fgetc(FILE *f)
{
/*等待接受完畢*/
while(USART_GetFlagStatus(USART,USART_FLAG_RXNE)==RESET);
return (USART_ReceiveData(USART));
}