基于stm32CubeMX和keil5的stm32f103學(xué)習(xí)編程
0. 準(zhǔn)備
先用st-link連接stm32核心板與PC,用于燒錄
再用USB串口板連接,用于查看串口輸出
安裝完成驅(qū)動并連接好以后,進入設(shè)備管理器可以看到它們都已被識別。
打開putty.exe,選擇串口連接,用于查看之后的串口輸出。
1. 編寫Cube程序,配置UART0為9600,8n1,上電后向串口輸出“Hello”,在PC上通過串口軟件觀察結(jié)果;
安裝完成并打開CubeMX軟件,選擇New Project,選擇STM32F103C8Tx并點擊ok。
進入工程界面以后我們可以看到右邊有芯片的引腳圖,如下所示。我們點擊PA11和PA12,選擇GPIO_Input(后面按鈕用)。然后在左邊的配置中將UART1模式定為Half-Duplex。
在生成代碼前,進入工程配置。填寫工程名、保存路徑等,同時選擇IDE為MDK-ARM V5。
設(shè)置完成后點擊生成代碼。注意如果沒安裝庫文件的話會提示下載,但通過軟件的自動更新速度無比的慢,而且經(jīng)常下一半會掛,所以可以在網(wǎng)絡(luò)上下載后自助導(dǎo)入。
生成代碼后彈出如下對話框,選擇open。
進入keil5以后可以看到我們的工程文件目錄如左欄所示。注意打開前會彈出Pack installer下載對應(yīng)的編程工具,選擇stm32f1xx系列即可。下載有點慢,可以自己下載或拷貝他人后導(dǎo)入,路徑為 c:/keil v5/ARM/Pack
然后進入main.c對UART進行配置為9600,8n1,代碼如下所示。
voidUART0_Init(UART_HandleTypeDef*UartHandle){
UartHandle->Instance=USART1;
UartHandle->Init.BaudRate=9600;
UartHandle->Init.WordLength=UART_WORDLENGTH_8B;
UartHandle->Init.StopBits=UART_STOPBITS_1;
UartHandle->Init.Parity=UART_PARITY_NONE;
UartHandle->Init.HwFlowCtl=UART_HWCONTROL_NONE;
UartHandle->Init.Mode=UART_MODE_TX_RX;
HAL_UART_Init(UartHandle);
}
在main函數(shù)中填上下面兩行代碼-
UART_HandleTypeDefUartHandle; UART0_Init(&UartHandle);
以及輸出hello的代碼
HAL_UART_Transmit(&UartHandle,(uint8_t*)”hellorn”,7,500);
完成代碼后,-準(zhǔn)備編譯。選擇flash-設(shè)置,進入Utilities標(biāo)簽,選擇settings,配置如下:
然后F7編譯完成后將程序燒錄至核心板,按一下板子上的reset開關(guān)就可以在putty看到串口輸出了。
2. 通過面包板在PA11和PA12各連接一個按鈕開關(guān)到地;
3. 編寫Cube程序,配置PA11和PA12為內(nèi)部上拉到輸入模式,在main()函數(shù)循環(huán)檢測PA11按鈕按下,并在按鈕按下時 在串口輸出“Pressed”;
可以在CubeMX中圖形化地更改引腳設(shè)置,也可以直接在代碼中修改:
voidMX_GPIO_Init(void)
{
……
GPIO_InitStruct.Mode=GPIO_MODE_INPUT;
GPIO_InitStruct.Pull=GPIO_PULLUP;
……
}
在while(1)中添加代碼,循環(huán)檢測并輸出
……
if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11))
HAL_UART_Transmit(&UartHandle,(uint8_t*)”Pressedrn”,9,500);
else
HAL_UART_Transmit(&UartHandle,(uint8_t*)”Notpressedrn”,13,500);
……
輸出如圖
4. 編寫Cube程序,配置PA12下降沿觸發(fā)中斷,程序中設(shè)置兩個全局變量,一個為計數(shù)器,一個為標(biāo)識。當(dāng)中斷觸發(fā) 時,計數(shù)器加1,并設(shè)置標(biāo)識。
在主循環(huán)中判斷標(biāo)識,如果標(biāo)識置位則清除標(biāo)識并通過串口輸出計數(shù)值;
在GPIO的init函數(shù)中為PIN12設(shè)置下降沿中斷,并設(shè)置優(yōu)先級。
GPIO_InitStruct.Pin=GPIO_PIN_12;
GPIO_InitStruct.Mode=GPIO_MODE_INPUT;
GPIO_InitStruct.Pull=GPIO_PULLUP;
GPIO_InitStruct.Mode=GPIO_MODE_IT_FALLING;
HAL_NVIC_SetPriority(EXTI15_10_IRQn,0,0);
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
PA12引腳的下降沿觸發(fā)將會觸發(fā)中斷,進入函數(shù)EXTI15_10_IRQHandler,此時在函數(shù)中調(diào)用HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_12)表示查看PA12的值,如果符合條件,則觸發(fā)HAL_GPIO_EXTI_Callback函數(shù)。代碼如下
voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){
if(GPIO_Pin==GPIO_PIN_12){
PA12flag=1;
PA12cnt++;
}else{
UNUSED(GPIO_Pin);
}
}
在main函數(shù)的while循環(huán)中添加代碼:
if(PA12flag==1){
PA12flag=0;
size=sprint(str,”Count:%drn”,PA12cnt);
HAL_UART_Transmit(&UartHandle,(uint8_t*)str,size,500);
}
5. 編寫Cube程序,開啟定時器為200ms中斷一次,中斷觸發(fā)時設(shè)置標(biāo)識,主循環(huán)根據(jù)這個標(biāo)識來做串口輸出(取消4 的串口輸出);
使用TIM3定時器,如果不是CUBEMX生成代碼的話記得添加頭文件引用。
添加init函數(shù):
voidTIM_Init(){
TIM_Handle.Instance=TIM3;
TIM_Handle.Init.Prescaler=8000;
TIM_Handle.Init.CounterMode=TIM_COUNTERMODE_UP;
TIM_Handle.Init.Period=199;
TIM_Handle.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&TIM_Handle);
sClockSourceConfig.ClockSource=TIM_CLOCKSOURCE_INTERNAL;//設(shè)置時鐘源為內(nèi)部時鐘
HAL_TIM_ConfigClockSource(&TIM_Handle,&sClockSourceConfig);
sMasterConfig.MasterOutputTrigger=TIM_TRGO_RESET;//設(shè)置復(fù)位模式,發(fā)生觸發(fā)輸入事件時計數(shù)器和預(yù)分頻器能重新初始化
sMasterConfig.MasterSlaveMode=TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&TIM_Handle,&sMasterConfig);
HAL_NVIC_SetPriority(TIM3_IRQn,0,0);//設(shè)置優(yōu)先級
HAL_NVIC_EnableIRQ(TIM3_IRQn);enable中斷向量表處理
}
和之前設(shè)置的中斷一樣需要覆寫中斷觸發(fā)函數(shù)TIM3_IRQHandler,而后在其中對時鐘進行判斷后觸發(fā)HAL_TIM_PeriodElapsedCallback。并在callback中實現(xiàn)操作。
TIM_HandleTypeDefTIM_Handle;
TIM_ClockConfigTypeDefsClockSourceConfig;
TIM_MasterConfigTypeDefsMasterConfig;
intTIMflag=0,PA12flag=0;
intTIMcnt=0,PA12cnt=0,totalcnt=0;
voidTIM3_IRQHandler(void){
HAL_TIM_IRQHandler(&TIM_Handle);
}
voidHAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef*htim){
TIMflag=1;
TIMcnt++;
}
6. 編寫完整的碼表程序,PA12的按鈕表示車輪轉(zhuǎn)了一圈,通過計數(shù)器可以得到里程,通過定時器中斷得到的時間可以計算出速度;PA11的按鈕切換模式,模式一在串口輸出里程,模式二在串口輸出速度。
在main函數(shù)中實現(xiàn)碼表程序:
while(1)
{
/*USERCODEENDWHILE*/
/*USERCODEBEGIN3*/
if(TIMflag==1){
TIMflag=0;
if(TIMcnt==5){每五個周期輸出一次
speed=2*PA12cnt/1;//五個周期為1秒,車輪周長2米