菜喵のSTM32F4學習筆記(1)USART
????這個系列的文章幾乎沒有怎么潤色,大約保留了自己學習過程中的原始筆記和debug記錄,部分內(nèi)容甚至很基礎(chǔ),bug出的也很沒水平,大家笑一笑就好2333。 ?
? 注1:本系列筆記中使用STM32F407ZGT6,利用STM32庫函數(shù)進行開發(fā); ?
??注2:個人筆記,記錄的是零散的知識,不對涉及到的背景知識進行的鋪開介紹(換句話說這不是一個成體系的可以視作學習用的教材的筆記,不過可以做交流參考~); ????
? 注3:啥時候B站專欄有代碼塊和公式啊qwq(每篇一問(笑))

????? ? 寫在筆記前:
????????關(guān)于STM32配置操作的部分內(nèi)容,個人感覺在了解了GPIO以及各個外設(shè)涉及到的寄存器之后,再來看各種庫函數(shù)會有一種啟明的感覺23333。
????????此時通過“到定義”的方式查看各個函數(shù)的實現(xiàn)也能比較容易地了解到這些亂七八糟的函數(shù)到底都在動那些寄存器、又干了些啥(筆記Note1中記錄的就是這樣的過程)。
????????稍微熟悉一點之后你甚至可以主動探索了:或者從各個外設(shè)的功能出發(fā),看對應(yīng)文件下定義的函數(shù)以及其中操作的寄存器;或者從文件出發(fā),通過看函數(shù)和寄存器反推這個外設(shè)在干嘛23333。

Note1:(這部分在研究GPIO復(fù)用操作(有點細過頭了2333))
?? ?首先,外設(shè)和GPIO不一定掛載在同一個時鐘上,所以可能要分別使能相關(guān)時鐘總線。STM32F4給了五個外設(shè)時鐘使能函數(shù):

一番搜索不難發(fā)現(xiàn)(stm32f4xx_rcc.h):


????????之后,注意到GPIO結(jié)構(gòu)體沒有涉及到對于AFRL &AFRH寄存器的操作,也就是說即使MODER寄存器里面選擇了復(fù)用功能,復(fù)用器也沒有配置。

????????查看GPIO_PinAFConfig函數(shù)定義(在stm32f4xx_gpio.c文件中 )可知,關(guān)于每一個GPIO口的復(fù)用器設(shè)置,還是需要用函數(shù)單獨操作一下的(GPIOx->AFR)

????????或者換句話說,你看完之后就知道為啥GPIO復(fù)用的時候還要用這樣一個函數(shù)了,而不是在GPIO_Init()中完成所有的定義(前提:你知道STM32F4當中都有哪些寄存器,分別有什么功能)。
????????不過這里我在想,?如果你足夠巨佬也足夠頑皮,你可以考慮修改一下庫函數(shù)的內(nèi)容(笑),比如把GPIO_PinAFConfig中的內(nèi)容改寫到GPIO_Init()當中,然后修改一下GPIO_InitTypeDef結(jié)構(gòu)體啥的(x),這樣你就可以少寫一兩行GPIO復(fù)用的代碼了,是不是很方便23333(x)。
????????對于GPIO_PinAFConfig()中可選用的GPIO_AF,在stm32f4xx_gpio.h中有定義(我用的是STM32F407,故而是這一段)

????????可以看到,串口USART、UART都在,不區(qū)分TX、RX;所以復(fù)用的時候直接設(shè)置為GPIO_AF_USART1就好。
? ? ????查閱芯片數(shù)據(jù)手冊得PA9、PA10 可擔當串口復(fù)用大任:

????????故最后GPIO復(fù)用如下:

????????這里就完成了將特定一組GPIO中的特定的IO口通過復(fù)用器連接到其對應(yīng)復(fù)用功能上的操作了。


試驗1:含中斷的串口發(fā)送試驗
????????第一次寫的主程序如下(Usart_Init();為串口初始化代碼,對串口1?進行初始化操作,后文有說明)


????????打印的應(yīng)該是ASCII碼,不過看起來,ASCII碼中確實不是所有的字符都是可打印的。


debug1:
????????看起來直接發(fā)送數(shù)據(jù)不太現(xiàn)實(或者我沒了解到),所以試著用字符串來實現(xiàn)收發(fā):

1、關(guān)于這里的字符串結(jié)尾,似乎必須寫成\r\n才能實現(xiàn)換行,單獨的\n不行
2、在輪詢發(fā)送data字符串的時候,有一個2ms的延時,如果這個延時沒有的話,運行效果是這個樣子的:


3、所以講道理除了延時應(yīng)該還有一個辦法:等待發(fā)送完成。故代碼應(yīng)該可以改成如下內(nèi)容:


bug修復(fù)!


Code1:
#include "stm32f4xx.h"
#include "delay.h"
void Usart_Init()
{
GPIO_InitTypeDef? GPIO_Struct;
USART_InitTypeDef USART_Struct;
NVIC_InitTypeDef NVIC_Struct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //初始化USART時鐘
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //初始化GPIO時鐘
//開啟GPIO復(fù)用
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);?
GPIO_Struct.GPIO_Mode = GPIO_Mode_AF;
GPIO_Struct.GPIO_OType = GPIO_OType_PP;
GPIO_Struct.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
GPIO_Struct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Struct.GPIO_Speed = GPIO_Speed_50MHz;
//初始化GPIO
GPIO_Init(GPIOA,&GPIO_Struct);?
USART_Struct.USART_BaudRate = 9600;
USART_Struct.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;
USART_Struct.USART_Parity = USART_Parity_No;
USART_Struct.USART_StopBits = USART_StopBits_1;
USART_Struct.USART_WordLength = USART_WordLength_8b;
USART_Struct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1,&USART_Struct);
USART_Cmd(USART1,ENABLE); //咋那么多使能2333
NVIC_Struct.NVIC_IRQChannel = USART1_IRQn;
NVIC_Struct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Struct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_Struct.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_Struct); // 初始化中斷
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //配置串口中斷標志位(接收觸發(fā))
}
//串口1 中斷服務(wù)函數(shù)
void USART1_IRQHandler(void)
{
????u8 res;
???? if(USART_GetITStatus(USART1,USART_IT_RXNE))
???? {
???????? res = USART_ReceiveData(USART1);
???????? USART_SendData(USART1,res);
???? }
}
//字符串長度獲取函數(shù)
int len(char * strdata)
{
???? char * point? = strdata;
???? int counter = 0;
???? while(*point!='\0')
???? {
???????? counter++;
???????? point++;
???? }
???? return counter;
}
//主函數(shù)
int main()
{
????char *data="Please Input Something\r\n";
????char *point;
????NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
????delay_init(168); //延時初始化
????Usart_Init();
????while(1)
????{
???? point = data;
???? delay_ms(1000);
???????? while(*point != data[len(data)])
???????? {
???????????? USART_SendData(USART1,*point);
???????????? point++;
???????????? while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);
?????????}
????}
}
運行結(jié)果如下所示:

????????然后既然初始化了中斷,我們就稍微皮一下。

????????發(fā)送數(shù)據(jù),周期設(shè)置為1ms,看看能不能破壞輪詢中向PC端發(fā)送的數(shù)據(jù)。
實驗結(jié)果:

????????這里應(yīng)該有兩次STM32發(fā)送給PC的信息"Please Input Something\r\n",第一次應(yīng)該是丟失了'P'、"\r\n";第二次應(yīng)該是丟失了'P' 't'?兩個字符。
????????也就是說,如果中斷和輪詢都要用到串口的話,是可能產(chǎn)生兩個發(fā)送信息交叉影響的結(jié)果的。所以如果之后用到遙控器或者別的通訊、特別是用同一個串口(或者別的信道)的時候,小心一點。

????????#MARK一下,這里我打算之后試一試在中斷服務(wù)函數(shù)中判斷SR寄存器,看看能不能做到兩個發(fā)送信息不沖突(起碼,不要丟失字符,哪怕兩條信息混在一起呢)
????????今天先不寫了,先去啃PWM的內(nèi)容233333 。
