本文代碼均來正點(diǎn)原子標(biāo)準(zhǔn)例程
聲明:本文不是教學(xué)文章,可能也不適合初學(xué)者閱讀
不知為什么,最近總蹦出有很多想法(可能是工作太閑了)一會(huì)想學(xué)這,一會(huì)想學(xué)那,這不,突然想復(fù)習(xí)一下STM32
了。
我好久以前就學(xué)過正點(diǎn)原子的課程,還買過一些開發(fā)板,但現(xiàn)在手上只有一個(gè)核心板了,就暫且湊合著用吧。
我是個(gè)喜歡制定計(jì)劃的人,既然有了想法,那就得制定一個(gè)學(xué)習(xí)計(jì)劃,估摸了一下,明天要上班,現(xiàn)在已經(jīng)中午了,所以我只有一個(gè)下午加一個(gè)晚上的時(shí)間。哎?,工作之后發(fā)現(xiàn)學(xué)習(xí)的時(shí)間太少了,所以,既然是復(fù)習(xí),那就不搞那么多彎彎繞繞了,直接針對(duì)正點(diǎn)原子的代碼,通過代碼學(xué)習(xí)STM32,那些啥原理的,通通給我拋到九霄云外去,以后有機(jī)會(huì)慢慢整。
話不多說,開始整活,先準(zhǔn)備一下硬件:
就一個(gè)核心板,太寒酸了,還好有個(gè)屏幕撐撐場面。核心板的MCU型號(hào)為STM32F103ZET6。
有了硬件,就差代碼了。
下圖是正點(diǎn)原子的入門篇視頻,我就按照這個(gè)順序來學(xué)一遍(沒有硬件支持的話,就只能跳過了,如OLED),寄存器版的就不考慮了,太麻煩。
雖然從教學(xué)視頻的目錄上看感覺實(shí)驗(yàn)多得有些嚇人,但打開工程文件夾一看,嘿嘿,舒服了。?,這么一點(diǎn),一下午就能搞完。
就在我竊喜的時(shí)候,看了一眼時(shí)間,時(shí)間不多了,抓緊了?。。。
光看主函數(shù),覺得他和51一樣簡單,就是初始化和設(shè)置GPIO的高低,但實(shí)際上它們有本質(zhì)區(qū)別,畢竟一個(gè)是8位,一個(gè)是32位。下面我們來一行行地分析吧。
int main(void){ delay_init(); //初始化延時(shí)函數(shù) LED_Init(); //初始化LED端口 while(1) { GPIO_ResetBits(GPIOB,GPIO_Pin_5); //LED0對(duì)應(yīng)引腳GPIOB.5拉低,亮 等同LED0=0; GPIO_SetBits(GPIOE,GPIO_Pin_5); //LED1對(duì)應(yīng)引腳GPIOE.5拉高,滅 等同LED1=1; delay_ms(300); //延時(shí)300ms GPIO_SetBits(GPIOB,GPIO_Pin_5); //LED0對(duì)應(yīng)引腳GPIOB.5拉高,滅 等同LED0=1; GPIO_ResetBits(GPIOE,GPIO_Pin_5); //LED1對(duì)應(yīng)引腳GPIOE.5拉低,亮 等同LED1=0; delay_ms(300); //延時(shí)300ms }}
//初始化延遲函數(shù)//SYSTICK的時(shí)鐘固定為HCLK時(shí)鐘的1/8//SYSCLK:系統(tǒng)時(shí)鐘void delay_init(){ SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //選擇外部時(shí)鐘 HCLK/8 fac_us=SystemCoreClock/8000000; //為系統(tǒng)時(shí)鐘的1/8 fac_ms=(u16)fac_us*1000; //非OS下,代表每個(gè)ms需要的systick時(shí)鐘數(shù) }
第一個(gè)函數(shù)delay_init()
,不像51里直接用一個(gè)while實(shí)現(xiàn)延時(shí),這里的延時(shí)由滴答定時(shí)器實(shí)現(xiàn)。Systick定時(shí)器就是系統(tǒng)滴答定時(shí)器,一個(gè)24 位的倒計(jì)數(shù)定時(shí)器,計(jì)到0 時(shí),將從RELOAD 寄存器中自動(dòng)重裝載定時(shí)初值。只要不把它在SysTick 控制及狀態(tài)寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。
SysTick_CLKSourceConfig
是一個(gè)庫函數(shù),作用是配置滴答定時(shí)器的時(shí)鐘源。
STM32 有5個(gè)時(shí)鐘源:HSI、HSE、LSI、LSE、PLL。
①、HSI是高速內(nèi)部時(shí)鐘,RC振蕩器,頻率為8MHz,精度不高。
②、HSE是高速外部時(shí)鐘,可接石英/陶瓷諧振器,或者接外部時(shí)鐘源,頻率范圍為4MHz~16MHz。
③、LSI是低速內(nèi)部時(shí)鐘,RC振蕩器,頻率為40kHz,提供低功耗時(shí)鐘。WDG
④、LSE是低速外部時(shí)鐘,接頻率為32.768kHz的石英晶體。RTC
⑤、PLL為鎖相環(huán)倍頻輸出,其時(shí)鐘輸入源可選擇為HSI/2、HSE或者HSE/2。
倍頻可選擇為2~16倍,但是其輸出頻率最大不得超過72MHz。
STM32時(shí)鐘源的知識(shí)還是挺多的,我自己現(xiàn)在也不是很清楚(得專門抽空學(xué)學(xué)),但我知道如果沒有做配置,系統(tǒng)默認(rèn)時(shí)鐘頻率是最高頻率——本平臺(tái)為72MHz
system_stm32f10x.c
里有以下內(nèi)容,先記錄一下,以后再分析。
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)/* #define SYSCLK_FREQ_HSE HSE_VALUE */ #define SYSCLK_FREQ_24MHz 24000000#else/* #define SYSCLK_FREQ_HSE HSE_VALUE *//* #define SYSCLK_FREQ_24MHz 24000000 */ /* #define SYSCLK_FREQ_36MHz 36000000 *//* #define SYSCLK_FREQ_48MHz 48000000 *//* #define SYSCLK_FREQ_56MHz 56000000 */#define SYSCLK_FREQ_72MHz 72000000#endif
下面看看滴答定時(shí)器時(shí)鐘源配置的庫函數(shù)源碼,可以看出它的時(shí)鐘源只能為SysTick_CLKSource_HCLK_Div8
或SysTick_CLKSource_HCLK
,那么問題來了,什么是HCLK:
HCLK :AHB總線時(shí)鐘,由系統(tǒng)時(shí)鐘SYSCLK 分頻得到,一般不分頻,等于系統(tǒng)時(shí)鐘
剛剛提到系統(tǒng)時(shí)鐘為72M,所以SysTick_CLKSource_HCLK_Div8 就是72/8=9M。
/** * @brief Configures the SysTick clock source. * @param SysTick_CLKSource: specifies the SysTick clock source. * This parameter can be one of the following values: * @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source. * @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source. * @retval None */void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource){ /* Check the parameters */ assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource)); if (SysTick_CLKSource == SysTick_CLKSource_HCLK) { SysTick->CTRL |= SysTick_CLKSource_HCLK; } else { SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8; }}
配置完了滴答定時(shí)器的時(shí)鐘,delay_init函數(shù)內(nèi)還有兩行:
fac_us=SystemCoreClock/8000000; //為系統(tǒng)時(shí)鐘的1/8 fac_ms=(u16)fac_us*1000; //非OS下,代表每個(gè)ms需要的systick時(shí)鐘數(shù)
fac_us表示微秒的計(jì)時(shí)因子,即滴答計(jì)時(shí)器重載值為1*fac_us時(shí),計(jì)時(shí)時(shí)間為1us(可以看后面的delay_us函數(shù)),fac_ms為fac_us的1000倍,自然就是1ms了。
之前我們提到
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //選擇外部時(shí)鐘 HCLK/8
即滴答定時(shí)器定時(shí)器頻率為9M(72/8),9M意味著定時(shí)器1秒計(jì)數(shù)9000000,那么1毫秒計(jì)數(shù)就為9000,1微秒為9。這代表什么?計(jì)9次數(shù)為1us,這個(gè)9就是1微秒的計(jì)數(shù)因子(fac_us),即fac_us(72000000/8000000=9)代表1us。n微秒則為n * fac_us。
終于到了本實(shí)驗(yàn)的主角——LED(GPIO)
//初始化PB5和PE5為輸出口.并使能這兩個(gè)口的時(shí)鐘 //LED IO初始化void LED_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); //使能PB,PE端口時(shí)鐘 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度為50MHz GPIO_Init(GPIOB, &GPIO_InitStructure); //根據(jù)設(shè)定參數(shù)初始化GPIOB.5 GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 輸出高 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED1-->PE.5 端口配置, 推挽輸出 GPIO_Init(GPIOE, &GPIO_InitStructure); //推挽輸出 ,IO口速度為50MHz GPIO_SetBits(GPIOE,GPIO_Pin_5); //PE.5 輸出高 }
概括一下配置GPIO的步驟:
RCC_APB2PeriphClockCmd(...)
GPIO_Pin
GPIO_Mode
GPIO_Speed
GPIO_Init(..)
GPIO_SetBits(..)
或GPIO_ResetBits(...)
庫函數(shù)注釋中標(biāo)明了時(shí)鐘總線上的外設(shè),GPIOB和GPIOE都在APB2總線上
/** * @brief Enables or disables the High Speed APB (APB2) peripheral clock. * @param RCC_APB2Periph: specifies the APB2 peripheral to gates its clock. * This parameter can be any combination of the following values: * @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB, * RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE, * RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1, * RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1, * RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3, * RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17, * RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11 * @param NewState: new state of the specified peripheral clock. * This parameter can be: ENABLE or DISABLE. * @retval None */void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState){ /* Check the parameters */ assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph)); assert_param(IS_FUNCTIONAL_STATE(NewState)); if (NewState != DISABLE) { RCC->APB2ENR |= RCC_APB2Periph; } else { RCC->APB2ENR &= ~RCC_APB2Periph; }}
如果想快速查到某外設(shè)的時(shí)鐘總線,可以參考《STM32中文參考手冊(cè)》存儲(chǔ)器和總線架構(gòu)章節(jié):
下面是GPIO_InitTypeDef
結(jié)構(gòu)體定義
/** * @brief GPIO Init structure definition */typedef struct{ uint16_t GPIO_Pin; /*!< Specifies the GPIO pins to be configured. This parameter can be any value of @ref GPIO_pins_define */ GPIOSpeed_TypeDef GPIO_Speed; /*!< Specifies the speed for the selected pins. This parameter can be a value of @ref GPIOSpeed_TypeDef */ GPIOMode_TypeDef GPIO_Mode; /*!< Specifies the operating mode for the selected pins. This parameter can be a value of @ref GPIOMode_TypeDef */}GPIO_InitTypeDef;
LED_init中,LED0
的GPIO_Pin
為GPIOB5,LED1
為GPIOE5;
模式都選擇了推挽輸出
推挽輸出的最大特點(diǎn)是可以真正能真正的輸出高電平和低電平,在兩種電平下都具有驅(qū)動(dòng)能力。
由LED的原理圖可以知道它們?yōu)楣碴枠O,所以默認(rèn)要將IO拉高。
其他細(xì)節(jié)感興趣的可以自己去研究?。
fac_ms剛剛在延時(shí)函數(shù)初始化中已經(jīng)介紹,滴答定時(shí)器SysTick每計(jì)時(shí)fac_ms次,則表示1ms,所以nms*fac_ms表示計(jì)時(shí)nms毫秒。SysTick->LOAD
為定時(shí)器的重載值,SysTick->VAL
表示計(jì)數(shù)值,還要注意:滴答定時(shí)器是倒數(shù)計(jì)數(shù)的。SysTick->CTRL
為控制寄存器,第16位可以用來檢測是否倒數(shù)到0。
void delay_ms(u16 nms){ u32 temp; SysTick->LOAD=(u32)nms*fac_ms; //時(shí)間加載(SysTick->LOAD為24bit) SysTick->VAL =0x00; //清空計(jì)數(shù)器 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //開始倒數(shù) do { temp=SysTick->CTRL; }while((temp&0x01)&&!(temp&(1<<16))); //等待時(shí)間到達(dá) SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //關(guān)閉計(jì)數(shù)器 SysTick->VAL =0X00; //清空計(jì)數(shù)器 }
對(duì)于操作寄存器,經(jīng)常要用到位操作,如SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk
中,SysTick_CTRL_ENABLE_Msk表示1,SysTick->CTRL|=1的作用是將CTRL寄存器的最低位置1,而不影響其他高19位(0或任何二進(jìn)制數(shù),都會(huì)是它自己);
而SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;
的作用是將CTRL最低位置0,0x00000001按位取反后為0xfffffffe,該數(shù)與任何32位數(shù)按位與(&),都不會(huì)影響高31位,因?yàn)?和任何二進(jìn)制數(shù)進(jìn)行與運(yùn)算都等于它自己。
本來想寫位帶操作的,但看了看時(shí)間,就放棄了
GPIO引腳控制函數(shù)就不提了,之前在LED_Init()函數(shù)里已經(jīng)見過。
實(shí)驗(yàn)效果——紅綠燈交替閃爍。
主函數(shù)中LED0、LED1和BEEP代表的是GPIO的位段(本文忽略這個(gè)概念),把它當(dāng)做51里對(duì)GPIO的位操作就行了。
與上一個(gè)實(shí)驗(yàn)相比,本實(shí)驗(yàn)多了按鍵模塊和蜂鳴器模塊。
int main(void) { vu8 key=0; delay_init(); //延時(shí)函數(shù)初始化 LED_Init(); //LED端口初始化 KEY_Init(); //初始化與按鍵連接的硬件接口 BEEP_Init(); //初始化蜂鳴器端口 LED0=0; //先點(diǎn)亮紅燈 while(1) { key=KEY_Scan(0); //得到鍵值 if(key) { switch(key) { case WKUP_PRES: //控制LED1翻轉(zhuǎn) LED1=!LED1; BEEP = !BEEP; break; case KEY0_PRES: //同時(shí)控制LED0翻轉(zhuǎn) LED0=!LED0; BEEP = !BEEP; break; } }else delay_ms(10); } }
與LED_Init()類似,配置步驟相同(配置步驟見LED_Init()介紹部分)。
void KEY_Init(void) //IO初始化{ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);//使能PORTA,PORTE時(shí)鐘 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;//KEY0 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //設(shè)置成下拉輸入 GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE2,3,4 //初始化 WK_UP-->GPIOA.0 下拉輸入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0設(shè)置成輸入,默認(rèn)下拉 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0}
開發(fā)板上有兩個(gè)按鍵,KEY_UP
和KEY0
,都是一端接高電平,一端接IO,所以模式設(shè)置為下拉輸入
,KEY_UP對(duì)應(yīng)的GPIO引腳為GPIOA0,KEY0對(duì)應(yīng)的引腳為GPIOE4。IO時(shí)鐘都掛載在APB2上。
開發(fā)板上并沒有蜂鳴器,我選擇了外接一個(gè)蜂鳴器,同樣接在PB8引腳上。初始化配置步驟和LED與KEY相同,模式為推挽輸出
,由于我的蜂鳴器低電平有效,所以初始化中還需把IO電平拉高。
//初始化PB8為輸出口.并使能這個(gè)口的時(shí)鐘 //蜂鳴器初始化void BEEP_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOB端口時(shí)鐘 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //BEEP-->PB.8 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度為50MHz GPIO_Init(GPIOB, &GPIO_InitStructure); //根據(jù)參數(shù)初始化GPIOB.8 GPIO_SetBits(GPIOB,GPIO_Pin_8);//輸出0,關(guān)閉蜂鳴器輸出}
該函數(shù)中,mode
表示模式,為0表示短按
,為1表示長按
。局部靜態(tài)變量key_up
默認(rèn)為1,表示按鍵處于空閑狀態(tài)(松開)。
如果選擇短按,在按鍵處于空閑狀態(tài)時(shí),檢測到KEY0
和WK_UP
中任意一個(gè)按鍵被按下,則將key_up
置0,在此期間不處理其他按鍵判斷,函數(shù)返回值為按鍵值或0(無按鍵);當(dāng)按鍵松開,程序再次運(yùn)行到按鍵掃描函數(shù)中時(shí),key_up
置為1,按鍵再次回到空閑狀態(tài)。
如果選擇長按,則key_up
恒為1,無論是否有按鍵正處于按下狀態(tài),每次進(jìn)入KEY_Scan函數(shù)都進(jìn)行按鍵判斷,這樣就實(shí)現(xiàn)了按鍵的長按檢測。
u8 KEY_Scan(u8 mode){ static u8 key_up=1;//按鍵按松開標(biāo)志 if(mode)key_up=1; //支持連按 if(key_up&&(KEY0==1||WK_UP==1)) { delay_ms(10);//去抖動(dòng) key_up=0; if(KEY0==1)return KEY0_PRES; else if(WK_UP==1)return WKUP_PRES; }else if(KEY0==0&&WK_UP==0)key_up=1; return 0;// 無按鍵按下}
與前兩個(gè)實(shí)驗(yàn)相比,串口實(shí)驗(yàn)增加了NVIC中斷配置、串口初始化配置。main函數(shù)實(shí)現(xiàn)的功能為:單片機(jī)不停地向串口發(fā)送提示性數(shù)據(jù),如果有外部設(shè)備通過串口向單片機(jī)發(fā)送數(shù)據(jù)(以“/r/n“作為結(jié)束符),單片機(jī)接收數(shù)據(jù)并返回給外部設(shè)備。
int main(void) { u16 t; u16 len; u16 times=0; delay_init(); //延時(shí)函數(shù)初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設(shè)置NVIC中斷分組2:2位搶占優(yōu)先級(jí),2位響應(yīng)優(yōu)先級(jí) uart_init(115200); //串口初始化為115200 LED_Init(); //LED端口初始化 KEY_Init(); //初始化與按鍵連接的硬件接口 while(1) { if(USART_RX_STA&0x8000) { len=USART_RX_STA&0x3fff;//得到此次接收到的數(shù)據(jù)長度 printf("/r/n您發(fā)送的消息為:/r/n/r/n"); for(t=0;t<len;t++) { USART_SendData(USART1, USART_RX_BUF[t]);//向串口1發(fā)送數(shù)據(jù) while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待發(fā)送結(jié)束 } printf("/r/n/r/n");//插入換行 USART_RX_STA=0; }else { times++; if(times%5000==0) { printf("/r/n戰(zhàn)艦STM32開發(fā)板 串口實(shí)驗(yàn)/r/n"); printf("正點(diǎn)原子@ALIENTEK/r/n/r/n"); } if(times%200==0)printf("請(qǐng)輸入數(shù)據(jù),以回車鍵結(jié)束/n"); if(times%30==0)LED0=!LED0;//閃爍LED,提示系統(tǒng)正在運(yùn)行. delay_ms(10); } } }
NVIC:嵌套向量中斷控制器,NVIC_PriorityGroupConfig
函數(shù)是中斷優(yōu)先級(jí)的分組配置函數(shù)。
/** * @brief Configures the priority grouping: pre-emption priority and subpriority. * @param NVIC_PriorityGroup: specifies the priority grouping bits length. * This parameter can be one of the following values: * @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority * 4 bits for subpriority * @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority * 3 bits for subpriority * @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority * 2 bits for subpriority * @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority * 1 bits for subpriority * @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority * 0 bits for subpriority * @retval None */void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup){ /* Check the parameters */ assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup)); /* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */ SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;}
中斷優(yōu)先級(jí)分為搶占式優(yōu)先級(jí)
和響應(yīng)優(yōu)先級(jí)
,搶占優(yōu)先級(jí)越高的先處理,當(dāng)兩個(gè)中斷向量的搶占優(yōu)先級(jí)相同時(shí),如果兩個(gè)中斷同時(shí)到達(dá), 則先處理響應(yīng)優(yōu)先級(jí)高的中斷。
如果對(duì)兩種優(yōu)先級(jí)的位數(shù)分配進(jìn)行分組,可以分為5組(0~4),分組配置是在寄存器SCB->AIRCR中配置:
main函數(shù)中,分組為:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設(shè)置NVIC中斷分組2:2位搶占優(yōu)先級(jí),2位響應(yīng)優(yōu)先級(jí)
注:這個(gè)分組只是設(shè)置STM32中斷的兩種優(yōu)先級(jí)可選范圍,比如0組中,沒有搶占優(yōu)先級(jí),一般情況(學(xué)習(xí)過程中)該配置設(shè)置為2組就行了。另外,這個(gè)分組是全局的,所以一個(gè)程序中只需要配置一次,多次配置可能會(huì)導(dǎo)致未知錯(cuò)誤。
串口初始化函數(shù)里不僅有GPIO初始化,還有UART初始化和NVIC初始化。
void uart_init(u32 bound){ //GPIO端口設(shè)置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA時(shí)鐘 //USART1_TX GPIOA.9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復(fù)用推挽輸出 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9 //USART1_RX GPIOA.10初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10 //Usart1 NVIC 配置 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//搶占優(yōu)先級(jí)3 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子優(yōu)先級(jí)3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 NVIC_Init(&NVIC_InitStructure); //根據(jù)指定的參數(shù)初始化VIC寄存器 //USART 初始化設(shè)置 USART_InitStructure.USART_BaudRate = bound;//串口波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長為8位數(shù)據(jù)格式 USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個(gè)停止位 USART_InitStructure.USART_Parity = USART_Parity_No;//無奇偶校驗(yàn)位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無硬件數(shù)據(jù)流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發(fā)模式 USART_Init(USART1, &USART_InitStructure); //初始化串口1 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開啟串口接受中斷 USART_Cmd(USART1, ENABLE); //使能串口1 }
從原理圖可知串口的發(fā)送IO為GPIOA9,接收IO為GPIOA10,TX(PA9)設(shè)置為復(fù)用推挽輸出(PA9為復(fù)用引腳,可以通過設(shè)置復(fù)用推挽輸出完成USART_TX功能的配置,另外還可以通過配合復(fù)用寄存器方式實(shí)現(xiàn)復(fù)用,如PWM實(shí)驗(yàn)),RX設(shè)置為浮空輸入。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/121284.html
摘要:此文章用于解決開發(fā)板的模塊中文字庫加載問題,也可用于其它關(guān)于中文字庫無法加載的問題。如下圖,已經(jīng)完成了中文字庫燒入,無需再掛載。 正點(diǎn)原子stm32mini板lor...
摘要:使用實(shí)現(xiàn)連網(wǎng)實(shí)現(xiàn)巴法云物聯(lián)網(wǎng)使用硬件程序思路基于正點(diǎn)原子的測試程序在巴法云物聯(lián)網(wǎng)創(chuàng)建的主題初始化代碼比較簡陋主函數(shù)代碼如果想用串口助手調(diào)試,接線方法如下使用硬件我這里使用的是正點(diǎn)原子家的開發(fā)板精英版和模塊。 ...
摘要:嚴(yán)格地說,應(yīng)該是模仿實(shí)驗(yàn)。為什么覺得無從下手,看資料沒有頭緒經(jīng)驗(yàn)總結(jié)看資料需要計(jì)劃耐心和速度這里所謂的資料包括書籍文檔。建議有報(bào)銷條件的同學(xué)自己設(shè)計(jì)一塊板子學(xué)習(xí)。無法報(bào)銷的同學(xué),可以選購一款開發(fā)板學(xué)習(xí)。 STM32系列基于專為要求高性能、低成本、低功耗的嵌入式應(yīng)用專門設(shè)計(jì)的ARMCortex...
摘要:基于開發(fā)的軟件包導(dǎo)師汪禮超學(xué)員崔林威摘要騰訊物聯(lián)網(wǎng)操作系統(tǒng)是騰訊面向物聯(lián)網(wǎng)領(lǐng)域開發(fā)的實(shí)時(shí)操作系統(tǒng),具有低功耗,低資源占用,模塊化,可裁剪等特性。圖中斷函數(shù)處理進(jìn)行生成工程配置,按如下界面進(jìn)行配置,最后點(diǎn)擊,并點(diǎn)擊。 ...
閱讀 2721·2023-04-26 02:28
閱讀 2551·2021-09-27 13:36
閱讀 3122·2021-09-03 10:29
閱讀 2751·2021-08-26 14:14
閱讀 2100·2019-08-30 15:56
閱讀 830·2019-08-29 13:46
閱讀 2608·2019-08-29 13:15
閱讀 454·2019-08-29 11:29