我的第一個(gè)項(xiàng)目是STM32嵌入式系統(tǒng)設(shè)計(jì)血筑,包括了硬件部分和軟件部分绘沉。項(xiàng)目與公共衛(wèi)生學(xué)院合作煎楣,主要內(nèi)容是關(guān)于藥劑檢測(cè)。
之前做過(guò)用51單片機(jī)開(kāi)發(fā)板讀取溫度濕度的小項(xiàng)目车伞,主要的任務(wù)是代碼的編寫择懂,相比于51單片機(jī)這種入門級(jí)別的MCU,STM32在各方面性能都領(lǐng)先51單片機(jī)另玖,但是使用起來(lái)也復(fù)雜不少困曙,光是選擇用庫(kù)函數(shù)法或是寄存器法編程就讓人糾結(jié)。
我主要通過(guò)視頻+相關(guān)文檔的方法來(lái)學(xué)習(xí)STM32谦去。
視頻地址:【正點(diǎn)原子】STM32開(kāi)發(fā)板實(shí)驗(yàn)教程赂弓,視頻講的很細(xì),電路原理圖也都有講哪轿,不過(guò)涉及到原理乏味而又高深盈魁。
相對(duì)應(yīng)的實(shí)驗(yàn)配套文檔:正點(diǎn)原子戰(zhàn)艦版資料
其中個(gè)人認(rèn)為最有用的是:
①軟件資料下的軟件壓縮包,有MDK5的安裝包和各種實(shí)用軟件窃诉,比如程序下載軟件杨耙、串口軟件
②STM32F1開(kāi)發(fā)指南,包括庫(kù)函數(shù)版和寄存器版飘痛。
③STM32參考資料文件夾下的STM32中文參考手冊(cè)
④STM32F103ZET6
⑤程序源碼珊膜,包括庫(kù)函數(shù)版和寄存器版。
STM32快速簡(jiǎn)介
我總結(jié)了下我對(duì)STM32的理解:
STM32是ST公司生產(chǎn)的MCU宣脉,32位车柠,內(nèi)核是ARM公司的Cortex內(nèi)核。Cortex內(nèi)核有A塑猖,R竹祷,M三個(gè)系列,STM32主要是Cortex-M系列羊苟。Cortex-M3內(nèi)核在各方面都領(lǐng)先于ARM7內(nèi)核塑陵,成本也更低。
配置程序的模板框架其實(shí)挺復(fù)雜的蜡励,但其實(shí)不需要自己一步一步的建立令花,直接套用程序源碼中的模板就好了。現(xiàn)成的有STM32F103系列和STM32F407系列的模板凉倚。
為了方便開(kāi)發(fā)兼都,我最后選擇的是庫(kù)函數(shù)法。本文以串口通信作為例子稽寒,盡量詳盡的給出模板扮碧,中間必須要用到的頭函數(shù)定義和GPIO函數(shù)也進(jìn)行了一定的介紹。
頭文件設(shè)置
#ifndef __XXX_H
#define __XXX_H
#include "XXXXXX.h"
void XXX//各種函數(shù)聲明
#define LED0 PAout(1)//各種宏定義瓦胎,PAout(1)這樣的位帶操作在sys.h中定義
#endif
GPIO的設(shè)置芬萍,包括輸入輸出
(1)初始化
GPIO_InitTypeDef GPIO_InitStructure; //定義名稱為GPIO_InitStructure的結(jié)構(gòu)體
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,數(shù)值感覺(jué)不太重要
GPIO_Init(GPIOB, &GPIO_InitStructure); //根據(jù)設(shè)定參數(shù)初始化GPIOB.5
其中GPIO_InitTypeDef是一個(gè)結(jié)構(gòu)體搔啊,主要包括GPIO的引腳柬祠、速度、模式三個(gè)參數(shù)负芋。
typedef struct
{
uint16_t GPIO_Pin; //GPIO_Pin_0到GPIO_Pin_15
GPIOSpeed_TypeDef GPIO_Speed;
GPIOMode_TypeDef GPIO_Mode;
}GPIO_InitTypeDef;
GPIO_Speed的參數(shù)規(guī)范為:
typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;
輸出模式必須配置漫蛔,輸入模式無(wú)須配置。設(shè)置端口的翻轉(zhuǎn)速度級(jí)別為50MHz旧蛾,這種級(jí)別時(shí)端口能輸出頻率很高的信號(hào)莽龟,但要求外設(shè)的容性負(fù)載很小。另外還有2MHz和10MHz級(jí)別的锨天,能驅(qū)動(dòng)容性負(fù)載較大的外設(shè)毯盈。
GPIO_Mode的參數(shù)規(guī)范為:
typedef enum
{ GPIO_Mode_AIN = 0x0, //模擬輸入
GPIO_Mode_IN_FLOATING = 0x04, //浮空輸入
GPIO_Mode_IPD = 0x28, //下拉輸入
GPIO_Mode_IPU = 0x48, //上拉輸入
GPIO_Mode_Out_OD = 0x14, //開(kāi)漏輸出
GPIO_Mode_Out_PP = 0x10, //通用推挽輸出
GPIO_Mode_AF_OD = 0x1C, //復(fù)用開(kāi)漏輸出
GPIO_Mode_AF_PP = 0x18 //復(fù)用推挽輸出
}GPIOMode_TypeDef;
各種輸出輸入模式應(yīng)用場(chǎng)合:
http://www.openedv.com/posts/list/21980.htm
(2)信號(hào)輸出和檢測(cè)輸入
有相應(yīng)的庫(kù)函數(shù)
GPIO_SetBits(GPIOE,GPIO_Pin_5); //LED1對(duì)應(yīng)引腳GPIOE.5拉高
GPIO_ResetBits(GPIOB,GPIO_Pin_5); //LED0對(duì)應(yīng)引腳GPIOB.5拉低
GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4);//讀取GPIOE.4的輸入
用位帶操作法比較方便
PAout(1) = 1;
PBin(2);
按鍵設(shè)置(以低電平觸發(fā)為例)
其中u8是無(wú)符號(hào)數(shù)字8位的意思,進(jìn)行過(guò)宏定義病袄。
//mode=0時(shí)搂赋,不支持連按;mode=1時(shí)益缠,支持連按
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;//按鍵按松開(kāi)標(biāo)志
if(mode)key_up=1; //支持連按
if(key_up&&(KEY0==0||KEY1==0||KEY2==0||WK_UP==1))
{
delay_ms(10);//去抖動(dòng)
key_up=0;
if(KEY0==0)return KEY0_PRES;
else if(KEY1==0)return KEY1_PRES;
else if(KEY2==0)return KEY2_PRES;
else if(WK_UP==1)return WKUP_PRES;
}else if(KEY0==1&&KEY1==1&&KEY2==1&&WK_UP==0)key_up=1;
return 0;// 無(wú)按鍵按下
}
串口通信
串口配置的一般步驟(以USART1為例脑奠,PA9為TX發(fā)送端,PA10為RX接收端為例):
①串口時(shí)鐘使能幅慌,GPIO時(shí)鐘使能:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);
其他串口可能是RCC_APB1PeriphClockCmd();
②串口復(fù)位(可不寫):
USART_DeInit(USART1);
③GPIO端口模式設(shè)置:
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復(fù)用推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);
④串口參數(shù)初始化:
USART_InitTypeDef USART_InittStructure;
USART_InittStructure.USART_BaudRate = 115200; //波特率
USART_InittStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流設(shè)置
USART_InittStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; //接收發(fā)送模式
USART_InittStructure.USART_Parity = USART_Parity_No; //奇偶校驗(yàn)位
USART_InittStructure.USART_StopBits = USART_StopBits_1; //停止位
USART_InittStructure.USART_WordLength = USART_WordLength_8b; //字長(zhǎng)
USART_Init(USART1, &USART_InittStructure);
⑤開(kāi)啟中斷并且初始化NVIC(如果需要開(kāi)啟中斷才需要這個(gè)步驟)
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //分組2宋欺,放到主函數(shù)main的開(kāi)頭位置
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //設(shè)置中斷類型,USART_IT_RXNE表示接收緩沖區(qū)非空
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //串口1中斷胰伍,在stm32F10x.h中有定義
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //搶占優(yōu)先級(jí)為1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //響應(yīng)優(yōu)先級(jí)為2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure);
⑥串口使能:
USART_Cmd(USART1, ENABLE);
⑦編寫中斷處理函數(shù):
//會(huì)和system文件夾里的usart.h有沖突齿诞,刪掉usart.h。
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
}
}
⑧串口數(shù)據(jù)收發(fā)操作:
USART_SendData(USART1, uint16_t Data);
USART_ReceiveData(USART1);
串口通信需要的軟硬件設(shè)置:
①安裝CH340驅(qū)動(dòng)(在軟件目錄下)骂租,讓電腦USB口能變成串口
②開(kāi)發(fā)板USB口選擇USB_232(如圖)
③PA9掌挚、PA10通過(guò)跳線帽分別與RXD蒿涎、TXD相連(如圖)
利用串口輸入指令控制程序
int main(void)
{
u16 len;
u8 flag = 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(); //初始化與按鍵連接的硬件接口
MCP9808_init(); //溫度傳感器初始化
while(1)
{
if(USART_RX_STA&0x8000) //第15位標(biāo)志位為1時(shí)表示接收完成
{
len=USART_RX_STA&0x3fff;//得到此次接收到的數(shù)據(jù)長(zhǎng)度嘉栓,第0位~第13位
if(USART_RX_BUF[len-1]=='E')//指令以E(END)結(jié)束
{
if(USART_RX_BUF[0]=='R'&USART_RX_BUF[1]=='T'&USART_RX_BUF[2]==' '&len==4) //指令為RT E
{
printf("溫度為%.2f℃\r\n",MCP9808_ReadTP()); //顯示溫度
flag = 0;
}
else
flag = 1;
}
else
flag = 1;
if(flag==1)
{
flag =0;
printf("錯(cuò)誤\r\n");
}
else
printf("代碼已執(zhí)行\(zhòng)r\n");
USART_RX_STA = 0;
}
}
}
可以根據(jù)需求再增加指令惊楼。
關(guān)于串口1下載程序:
orient/strip%7CimageView2/2/w/1240)
BOOT0=1,BOOT1=0校哎,如果下載一直識(shí)別不出來(lái)屈扎,嘗試按一按RST鍵掸刊。
下載完成后摄闸,由于軟件勾上了編成后執(zhí)行云茸,程序會(huì)開(kāi)始執(zhí)行是目。
若需要按RST鍵復(fù)位程序,需要再把BOOT0拉低标捺。否則按RST鍵程序不會(huì)執(zhí)行懊纳。