學(xué)習(xí)過程中的注意點(diǎn):
1.注意頭文件和C文件的包含關(guān)系,C文件自身應(yīng)包含自身的H頭文件以及用到的外部頭文件,而自身頭文件只需包含頭文件需要用到的資源文件即可。
參考文獻(xiàn):http://t.csdn.cn/o2GmL
一、認(rèn)識(shí)STM32
1.簡(jiǎn)介
2.命名規(guī)則??
3.系統(tǒng)結(jié)構(gòu)
4.引腳&功能
注釋:
紅色表示:與電源相關(guān)
藍(lán)色是最小系統(tǒng)相關(guān)的引腳
綠色是IO口、功能口
S代表電源、I代表輸入、O代表輸出、IO代表輸入輸出、FT代表能容忍5v電壓(沒有就是3.3v)
芯片上小黑點(diǎn)旁為第一個(gè)IO口,逆時(shí)針增加;
5.啟動(dòng)配置 (BOOT三種模式)
6.實(shí)物電路連接及Keil的設(shè)置?(ST-Link)
二、軟件環(huán)境安裝(MDK)及新建工程
1.MDK的安裝
stm32不同于C51,需要安裝ARM_mdk的版本;
keil5及之后的版本需要安裝芯片對(duì)應(yīng)系列的器件庫(pack);
stm的編程模式除了像單片機(jī)那樣(1)直接操作寄存器(更可靠但是復(fù)雜、麻煩),還有通過(2)使用官方封裝好的庫函數(shù),還有一種方法是(3)使用Hal庫(如使用STM32CubeMX軟件實(shí)現(xiàn)自動(dòng)初始化配置)。
安裝過程不在過多贅述,CSDN上有實(shí)現(xiàn)C51、ARM、C251三版共存的方法。
2.新建工程
因?yàn)椴捎玫氖?span style="color:#fe2c24;">使用官方封裝好的庫函數(shù),所以并不像之前配置單片機(jī)那樣去簡(jiǎn)單的只插入頭文件然后寫程序就好,而是先導(dǎo)入官方的啟動(dòng)文件,搭建環(huán)境。
2.1 配置成寄存器開發(fā)模式(工程)(詳細(xì)步驟)
1.建立啟動(dòng)文件夾start,導(dǎo)入啟動(dòng)文件
啟動(dòng)文件 必要頭文件 內(nèi)核的寄存器描述文件以及配置函數(shù)庫 成為這樣 ? ? ? ? 這里注意:上圖中的md.s后綴文件是根據(jù)單片機(jī)型號(hào)選擇的,參考下圖
2.建立用戶文件夾User
? ? ? ? 創(chuàng)建main.c
3.完成
2.1.1?寄存器開發(fā)模式下實(shí)現(xiàn)點(diǎn)亮LED(GPIO13)
1.首先打開RCC寄存器的APB2使能GPIOC的時(shí)鐘
2.再配置對(duì)應(yīng)的GPIOC的模式
3.再寫入該GPIOC的輸出數(shù)據(jù)
????????燈是低電平點(diǎn)亮,高電平熄滅
4.完成
5.總結(jié)收獲
通過該方法配置很繁瑣,且每次配置會(huì)影響其它IO口的數(shù)據(jù),只能通過像單片機(jī)中的&=、|=來解決,更麻煩。
2.2 配置成標(biāo)準(zhǔn)庫開發(fā)模式(工程)(詳細(xì)步驟)
1.在寄存器開發(fā)模板的基礎(chǔ)上,新建Lirary文件夾,導(dǎo)入c文件、頭文件
? ? ? ? ?全部粘貼到剛建立的文件夾Library
? ? ? ? 將這三個(gè)粘貼到User文件夾(下面需要在Keil里配置路徑)
2.在Keil里添加上述文件,配置Keil
一定要定義 USE_STDPERIPH_DRIVER
? ? ? ? USE使用、下劃線、STD標(biāo)準(zhǔn)、PERIPH外設(shè)、下劃線、DRIVER驅(qū)動(dòng)
自己定義的帶有頭文件的文件夾都需要添加入路徑 ?3.完成!
編譯0錯(cuò)誤0警告
2.2.1 標(biāo)準(zhǔn)庫開發(fā)模式下實(shí)現(xiàn)點(diǎn)亮LED(GPIO13)
配置思路和配置庫函數(shù)一樣,不同在于不用查手冊(cè)看具體位以及擔(dān)心改變其它位的數(shù)據(jù)了
操作流程還是一樣的
1.使能RCC寄存器控制的APB2總線上的外設(shè)IO時(shí)鐘
2.配置目標(biāo)外設(shè)的模式
? ? ? ? 這里注意:由于庫函數(shù)定義的GPIO_Init函數(shù)需要傳入一個(gè)結(jié)構(gòu)體變量的地址,這里是將需要配置的 Pin口、Speed傳輸速度、Mode輸出模式 三個(gè)封裝在了結(jié)構(gòu)體里以此簡(jiǎn)化了代碼。我們調(diào)用前必須要先自定義該結(jié)構(gòu)體類型的變量。
3.配置GPIOC_Pin口輸出的數(shù)據(jù)
? ? GPIO_SetBits (GPIOC,GPIO_Pin_13); ?//輸出高電平(熄滅)
?? ?GPIO_ResetBits (GPIOC,GPIO_Pin_13); ?//輸出低電平(點(diǎn)亮)#include "stm32f10x.h" // Device header int main(void) { // RCC->APB2ENR = 0X00000010; //配置寄存器實(shí)現(xiàn)點(diǎn)燈 // GPIOC->CRH = 0X00300000; // GPIOC->ODR = 0X00000000; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//使能GPIOC時(shí)鐘 GPIO_InitTypeDef GPIO_InitStruct; //定義的結(jié)構(gòu)體 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //輸出模式 GPIO_InitStruct .GPIO_Pin = GPIO_Pin_13; //輸出IO口 GPIO_InitStruct .GPIO_Speed = GPIO_Speed_50MHz; //輸出速度 GPIO_Init(GPIOC,&GPIO_InitStruct); //配置GPIOC的模式,這里將三種模式放在了一個(gè)結(jié)構(gòu)體內(nèi),因此要在上面定義一個(gè)結(jié)構(gòu)體 //GPIO_SetBits (GPIOC,GPIO_Pin_13); //輸出高電平(熄滅) GPIO_ResetBits (GPIOC,GPIO_Pin_13); //輸出低電平(點(diǎn)亮) while(1) { } }
3.工程架構(gòu)
4.步驟回顧、總結(jié)
三、GPIO(外設(shè))
1.GPIO結(jié)構(gòu)及原理
1.1 介紹
1.2 結(jié)構(gòu)?
簡(jiǎn)單來說,GPIO是受RCC寄存器?控制的APB2總線上的一系列外設(shè)IO口。
這些IO口由 GPIO A~GPIO E ,而單個(gè)GPIO如GPIOC都是又下分為16個(gè)小IO口(引腳),其中驅(qū)動(dòng)器是為了增加引腳電平驅(qū)動(dòng)能力
單個(gè)外設(shè)口如GPIOC的內(nèi)部電路結(jié)構(gòu)如下:
? ? ? ? 下圖中的肖特基觸發(fā)器是文獻(xiàn)翻譯錯(cuò)誤,實(shí)際應(yīng)為施密特觸發(fā)器。
?施密特觸發(fā)器原理:
? ? ? ? 內(nèi)部可設(shè)兩個(gè)閾值,輸入信號(hào)高于上限才為高電平,低于下限才為低電平
1.3 GPIO的八種模式
typedef enum
{ GPIO_Mode_AIN = 0x0,
? GPIO_Mode_IN_FLOATING = 0x04,
? GPIO_Mode_IPD = 0x28,
? GPIO_Mode_IPU = 0x48,
? GPIO_Mode_Out_OD = 0x14,
? GPIO_Mode_Out_PP = 0x10,
? GPIO_Mode_AF_OD = 0x1C,
? GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeDef;Stm32庫里將8種模式定義為了枚舉類型
GPIO_Mode_AIN
:模擬輸入模式(Analog Input Mode)。GPIO_Mode_IN_FLOATING
:浮空輸入模式(Floating Input Mode)。GPIO_Mode_IPD
:下拉輸入模式(Input Pull-down Mode)。GPIO_Mode_IPU
:上拉輸入模式(Input Pull-up Mode)。GPIO_Mode_Out_OD
:開漏輸出模式(Output Open-drain Mode)。GPIO_Mode_Out_PP
:推挽輸出模式(Output Push-pull Mode)。GPIO_Mode_AF_OD
:復(fù)用開漏輸出模式(Alternate Function Output Open-drain Mode)。GPIO_Mode_AF_PP
:復(fù)用推挽輸出模式(Alternate Function Output Push-pull Mode)。
2.GPIO輸出
2.1 可輸出設(shè)備(LED、蜂鳴器...)
和51單片機(jī)一樣,每個(gè)IO口都具有輸出功能(高低電平)
因此可實(shí)現(xiàn)點(diǎn)亮LED,蜂鳴器報(bào)警等功能。
2.2Stm32中LED、蜂鳴器的電路
2.3 面包板(結(jié)構(gòu))
2.4 實(shí)現(xiàn)LED閃爍(含代碼)
一定要先按照自己的思路和理解去寫一遍,主要就是調(diào)用各種庫函數(shù)。
下面代碼需要注意的是:
GPIO_InitTypeDef A,B,C; ?//定義三個(gè)IO的結(jié)構(gòu)體變量 A是PA0口、B是PA1口、C是PA3口
這段代碼如果在函數(shù)中間定義會(huì)報(bào)錯(cuò),那么是由于你的Keil版本過低導(dǎo)致,按下圖設(shè)置:
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE );//使能GPIO時(shí)鐘
GPIO_InitTypeDef A,B,C; //定義三個(gè)GPIO的結(jié)構(gòu)體變量 A是GPIOA、B是GPIOB、C是GPIOC//這里理解也不對(duì),因?yàn)锳BC只在RCC那里使能打開,這里定義的只是變量名,只是一個(gè)中間媒介去實(shí)現(xiàn)傳值
A.GPIO_Mode=GPIO_Mode_Out_PP;//設(shè)置為推挽輸出模式
A.GPIO_Pin=GPIO_Pin_0; //設(shè)置為Pin0口
A.GPIO_Speed=GPIO_Speed_50MHz; //輸出速度為50MHz
GPIO_Init( GPIOA,&A); //以上三個(gè)都要傳入該函數(shù)初始化
B.GPIO_Mode=GPIO_Mode_Out_PP;
B.GPIO_Pin=GPIO_Pin_1;
B.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init( GPIOA,&B);
C.GPIO_Mode=GPIO_Mode_Out_PP;
C.GPIO_Pin=GPIO_Pin_2;
C.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init( GPIOA,&C);
while(1)
{
GPIO_ResetBits (GPIOA,GPIO_Pin_0);//先亮
GPIO_ResetBits (GPIOA,GPIO_Pin_1);
GPIO_ResetBits (GPIOA,GPIO_Pin_2);
Delay_ms(500);
GPIO_SetBits (GPIOA,GPIO_Pin_0);//再滅
GPIO_SetBits (GPIOA,GPIO_Pin_1);
GPIO_SetBits (GPIOA,GPIO_Pin_2);
Delay_ms(500);
}
}
不知道你是否發(fā)現(xiàn),其實(shí)代碼里是定義了三個(gè)外設(shè),每個(gè)外設(shè)又單獨(dú)設(shè)置的IO,其實(shí)這種方法是不對(duì)的,也是初學(xué)時(shí)容易產(chǎn)生的誤區(qū),如何修改,看下面的代碼。
2.5 實(shí)現(xiàn)LED流水燈(含代碼、理解)
?初始化時(shí)是初始化一個(gè)外設(shè),然后一個(gè)外設(shè)又有16個(gè)引腳。
上面的代碼中 GPIO_InitTypeDef A,B,C; ?//定義三個(gè)GPIO的結(jié)構(gòu)體變量 A是GPIOA、B是GPIOB、C是GPIOC
這里理解也不對(duì),因?yàn)锳BC只在RCC寄存器那里使能打開,這里定義的只是變量名,只是一個(gè)中間媒介去實(shí)現(xiàn)傳值
個(gè)人覺得這樣定義可以實(shí)現(xiàn)一個(gè)外設(shè)例如GPIOA的16個(gè)引腳可以設(shè)置為不同的輸出模式。
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE );//使能GPIO時(shí)鐘
GPIO_InitTypeDef A; //定義一個(gè)中間結(jié)構(gòu)體變量
A.GPIO_Mode=GPIO_Mode_Out_PP;//設(shè)置為推挽輸出模式
A.GPIO_Pin=GPIO_Pin_All; //設(shè)置所有的Pin口(PA0~PA15)
A.GPIO_Speed=GPIO_Speed_50MHz; //輸出速度為50MHz
GPIO_Init( GPIOA,&A); //以上三個(gè)都要傳入該函數(shù)初始化
while(1)
{
unsigned char i;
for(i=0;i<8;i++)
{
GPIO_Write(GPIOA ,~(0X0001<<i));//0000 0000 0000 0001依次左移8位 該函數(shù)可以整體寫入GPIOx->ODR
Delay_ms(100);
}
}
}
2.6 蜂鳴器(含代碼)
?配置原理和配LED是一樣的
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE );//使能GPIO時(shí)鐘
GPIO_InitTypeDef A;
A.GPIO_Mode=GPIO_Mode_Out_PP;//設(shè)置為推挽輸出模式
A.GPIO_Pin=GPIO_Pin_12; //設(shè)置為Pin0口
A.GPIO_Speed=GPIO_Speed_50MHz; //輸出速度為50MHz
GPIO_Init( GPIOB,&A); //以上三個(gè)都要傳入該函數(shù)初始化
while(1)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_12);//低電平觸發(fā)
Delay_ms (100);
GPIO_SetBits(GPIOB,GPIO_Pin_12);//不響
Delay_ms (100);
}
}
3.GPIO輸入
3.1 可輸入設(shè)備(按鍵、溫濕度...)
3.2 Stm32中按鍵、紅外發(fā)射等器件的電路
3.3 復(fù)習(xí)數(shù)據(jù)類型、宏定義、Typedef、結(jié)構(gòu)體、枚舉
?define能改變?nèi)魏螖?shù)據(jù)的名字,但是編譯器不會(huì)檢測(cè)是否有錯(cuò)
?Typedef和結(jié)構(gòu)體相關(guān)的用法和說明可以看我的另外一篇文章
http://t.csdn.cn/H8ikF
枚舉類似于結(jié)構(gòu)體,其中關(guān)鍵詞 enum相當(dāng)于結(jié)構(gòu)體的關(guān)鍵詞 struct;
注意enum中是用逗號(hào)分隔;
枚舉的作用就是限制變量值的輸入取值范圍,就像星期幾只能從七天里選一個(gè);
取值超出范圍會(huì)報(bào)錯(cuò);
下附釋義代碼
#include <stdio.h>
int main()
{
typedef enum{
mon=1,
tur, // 等效于mon=1,tur=2,wen=3,tue=4
wen,
tue
}day;//這里將整個(gè)枚舉改名為day
day a,b,c;
int d;
a=tur;
b=(day)1;//直接賦值int型不行 ,需要轉(zhuǎn)化為枚舉型
c=day(4);
d=wen;//外界數(shù)據(jù)也可以引用枚舉集合里的數(shù)
printf("a=%d\n",a);
printf("b=%d\n",b);
printf("c=%d\n",c);
printf("d=%d\n",d);
}
3.4?代碼(按鍵控制LED)(封裝)(Delay函數(shù)封裝)
Stm32中延時(shí)函數(shù)Delay的us、ms、s的代碼
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
/***************************************************/延時(shí)函數(shù)模塊
#include "Delay.h"
#include "stm32f10x.h"
/**
* @brief 微秒級(jí)延時(shí)
* @param xus 延時(shí)時(shí)長(zhǎng),范圍:0~233015
* @retval 無
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //設(shè)置定時(shí)器重裝值
SysTick->VAL = 0x00; //清空當(dāng)前計(jì)數(shù)值
SysTick->CTRL = 0x00000005; //設(shè)置時(shí)鐘源為HCLK,啟動(dòng)定時(shí)器
while(!(SysTick->CTRL & 0x00010000)); //等待計(jì)數(shù)到0
SysTick->CTRL = 0x00000004; //關(guān)閉定時(shí)器
}
/**
* @brief 毫秒級(jí)延時(shí)
* @param xms 延時(shí)時(shí)長(zhǎng),范圍:0~4294967295
* @retval 無
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
/**
* @brief 秒級(jí)延時(shí)
* @param xs 延時(shí)時(shí)長(zhǎng),范圍:0~4294967295
* @retval 無
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
/***************************************************/LED模塊
#include "LED.h"
#include "stm32f10x.h" // Device header
void LED_init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE );//使能GPIOA的時(shí)鐘
GPIO_InitTypeDef A; //定義兩個(gè)IO的結(jié)構(gòu)體變量 A是PA0口、B是PB0口
A.GPIO_Mode=GPIO_Mode_Out_PP;//設(shè)置為推挽輸出模式
A.GPIO_Pin=GPIO_Pin_All; //設(shè)置為所有Pin口
A.GPIO_Speed=GPIO_Speed_50MHz; //輸出速度為50MHz
GPIO_Init( GPIOA,&A); //以上三個(gè)都要傳入該函數(shù)初始化
}
void LED_state(uint16_t GPIO_Pin,FunctionalState NewState)//指定Pin口和對(duì)應(yīng)狀態(tài)
{
if(NewState==0)
GPIO_ResetBits(GPIOA,GPIO_Pin);//置低電平
else
GPIO_SetBits(GPIOA,GPIO_Pin);//置高電平
}
/***************************************************/按鍵模塊
#include "Key.h" // Device header
#include "Delay.h"
void Key_init(uint16_t GPIO_Pin)//需要指定端口Pin進(jìn)行模式設(shè)置
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE );//使能GPIOA的時(shí)鐘
GPIO_InitTypeDef A; //定義兩個(gè)IO的結(jié)構(gòu)體變量 A是PA0口、B是PB0口
A.GPIO_Mode=GPIO_Mode_IPU;//設(shè)置為 上拉輸入 模式
A.GPIO_Pin=GPIO_Pin; //外界參數(shù)設(shè)置Pin口
A.GPIO_Speed=GPIO_Speed_50MHz; //輸出速度為50MHz,在輸入模式下該設(shè)置沒用
GPIO_Init( GPIOB,&A); //以上三個(gè)都要傳入該函數(shù)初始化
}
uint8_t get_keynum(uint16_t GPIO_Pin)
{
uint8_t keynum;
keynum =GPIO_ReadInputDataBit(GPIOB,GPIO_Pin);
if(keynum ==0)
{
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin) ==0);
Delay_ms(10);
return 0;
}
else
return keynum ;
}
/***************************************************/主函數(shù)
int main(void)
{
uint8_t state=0;
LED_init();
Key_init(GPIO_Pin_12);
while(1)
{
if(get_keynum(GPIO_Pin_12) ==0)
{
state ++;
}
if(state %2)
{
LED_state(GPIO_Pin_All ,ENABLE);
}
else
{
LED_state(GPIO_Pin_All,DISABLE);
}
}
}
/*********************阿布君***********************/
/****************編碼不易,謝謝關(guān)注*****************/
/****************QQ:2062808868********************/
3.5 代碼(光敏電阻控制蜂鳴器及LED)(封裝)
#include "stm32f10x.h" // Device header
#include "Buzzer.h"
#include "LightR.h"
#include "LED.h"
/***************************************************/蜂鳴器模塊
#include "Buzzer.h" // Device header
#include "stm32f10x.h"
GPIO_InitTypeDef buzzer;
void Buzzer_init(uint16_t GPIO_Pin)//需要指定端口Pin進(jìn)行模式設(shè)置
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE );//使能GPIOB的時(shí)鐘
buzzer.GPIO_Mode=GPIO_Mode_Out_PP;//設(shè)置為推挽輸出模式
buzzer.GPIO_Pin=GPIO_Pin; //外界參數(shù)設(shè)置Pin口
buzzer.GPIO_Speed=GPIO_Speed_50MHz; //輸出速度為50MHz,在輸入模式下該設(shè)置沒用
GPIO_Init( GPIOB,&buzzer); //以上三個(gè)都要傳入該函數(shù)初始化
}
void Buzzer_run(unsigned char Flag)//設(shè)定運(yùn)行標(biāo)志位
{
if(Flag==0)
GPIO_ResetBits(GPIOB,buzzer.GPIO_Pin);//置低電平
else
GPIO_SetBits(GPIOB,buzzer.GPIO_Pin);//置高電平
}
/***************************************************/光敏電阻模塊
#include "LightR.h"
#include "stm32f10x.h"
GPIO_InitTypeDef lightr;
void LightR_init(uint16_t GPIO_Pin)//需要指定端口Pin進(jìn)行模式設(shè)置
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE);//使能GPIOB的時(shí)鐘
lightr.GPIO_Mode=GPIO_Mode_IPU;//設(shè)置為 上拉輸入 模式
lightr.GPIO_Pin=GPIO_Pin; //外界參數(shù)設(shè)置Pin口
lightr.GPIO_Speed=GPIO_Speed_50MHz; //輸出速度為50MHz,在輸入模式下該設(shè)置沒用
GPIO_Init( GPIOB,&lightr); //以上三個(gè)都要傳入該函數(shù)初始化
}
uint8_t get_LightR_DO(void)//用來獲取光敏電阻輸出的數(shù)字量DO值
{
return GPIO_ReadInputDataBit(GPIOB,lightr.GPIO_Pin);
}
/***************************************************/LED模塊
#include "LED.h"
#include "stm32f10x.h" // Device header
GPIO_InitTypeDef led; //定義兩個(gè)IO的結(jié)構(gòu)體變量 A是PA0口、B是PB0口
void LED_init(uint16_t GPIO_Pin)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE );//使能GPIOA的時(shí)鐘
led .GPIO_Mode=GPIO_Mode_Out_PP;//設(shè)置為推挽輸出模式
led .GPIO_Pin=GPIO_Pin; //設(shè)置為所有Pin口
led .GPIO_Speed=GPIO_Speed_50MHz; //輸出速度為50MHz
GPIO_Init( GPIOA,&led ); //以上三個(gè)都要傳入該函數(shù)初始化
}
void LED_state(unsigned char Flag)//指定Pin口和對(duì)應(yīng)狀態(tài)
{
if(Flag==0)
GPIO_ResetBits(GPIOA,led.GPIO_Pin);//置低電平
else
GPIO_SetBits(GPIOA,led.GPIO_Pin);//置高電平
}
/***************************************************/主函數(shù)
int main(void)
{
uint16_t lightstate;//亮、暗狀態(tài)
LED_init(GPIO_Pin_0);
Buzzer_init(GPIO_Pin_0);
LightR_init(GPIO_Pin_1);
while(1)
{
lightstate =get_LightR_DO();//循環(huán)里實(shí)時(shí)獲取
if(lightstate)//暗 燈滅、蜂鳴器響
{
LED_state(1);
Buzzer_run(0);
}
else //亮 燈亮、蜂鳴器不響
{
LED_state(0);
Buzzer_run(1);
}
}
}
/*********************阿布君***********************/
/****************編碼不易,謝謝關(guān)注*****************/
/****************QQ:2062808868********************/
四、OLED顯示屏
1.結(jié)構(gòu)原理
1.1 結(jié)構(gòu)圖(0.96寸4針B版本)
1.2 介紹
1.3 電路
1.4 調(diào)試方法
2.OLED驅(qū)動(dòng)函數(shù)
3.驅(qū)動(dòng)函數(shù)封裝包
見資源包
五、EXTI外部中斷系統(tǒng)
1.結(jié)構(gòu)原理
1.1 認(rèn)識(shí)中斷
和C51中的中斷是一樣的,只不過32的資源更加豐富;??
1.2 中斷系統(tǒng)內(nèi)部機(jī)制(中斷和異常向表)
?????????由于Stm32中斷資源眾多,所以這里的中斷都是由NVIC統(tǒng)一管理。
左邊需要執(zhí)行的眾多中斷會(huì)根據(jù)分組和優(yōu)先級(jí)排隊(duì),其中搶占優(yōu)先級(jí)具有最高優(yōu)先級(jí)(可直接由NVIC傳入CPU,中斷CPU正在執(zhí)行的主程序或者中斷),而響應(yīng)優(yōu)先級(jí)則具有插隊(duì)排第一位的權(quán)限(優(yōu)先級(jí)次于搶占優(yōu)先級(jí)),當(dāng)左邊排隊(duì)完成,NVIC會(huì)根據(jù)左邊的排隊(duì)決定當(dāng)前該執(zhí)行哪一個(gè)中斷然后傳給CPU(CPU不知道優(yōu)先級(jí)邏輯,由NVIC處理,節(jié)約算力和IO口)
?中斷和異常向表,建議翻看手冊(cè);
1.3 EXTI簡(jiǎn)介
觸發(fā)中斷,中斷響應(yīng)是正常的流程,但是Stm32還提供了一種額外的中斷處理:事件響應(yīng)。
當(dāng)選擇觸發(fā)事件響應(yīng),那么該中斷信號(hào)將不會(huì)通過NVIC傳入CPU,而是直接傳給某一個(gè)外設(shè)并觸發(fā)它。例如觸發(fā)ADC模塊‘觸發(fā)DMA等。
總結(jié):中斷響應(yīng)是正常的流程,引腳電平變化觸發(fā)中斷。事件響應(yīng)不會(huì)觸發(fā)中斷,而是觸發(fā)別的外設(shè)操作,屬于外設(shè)之間的聯(lián)合操作。
注意:相同的pin口的中斷不能同時(shí)被觸發(fā),如PA0、PB0、PC0三個(gè)中斷同時(shí)需要傳入NVIC,但是最終只會(huì)有一個(gè)被傳入。
在EXTI內(nèi)部有對(duì)數(shù)據(jù)篩選處理的模塊,最終只有指定的IO數(shù)據(jù)會(huì)傳入NVIC,其它的會(huì)作為事件觸發(fā)傳給指定的外設(shè)。
1.4?EXTI機(jī)制
1.5 AFIO復(fù)用IO口
2.點(diǎn)觸式旋轉(zhuǎn)編碼器
2.1 結(jié)構(gòu)原理
?2.2 代碼實(shí)現(xiàn)(詳細(xì)步驟說明)
該模塊需要用到中斷,如何實(shí)現(xiàn)呢?其實(shí)原理就是將模塊IO口使能使其數(shù)據(jù)能夠到達(dá)NVIC再到CPU就好了。
五個(gè)步驟:
1.打開對(duì)應(yīng)IO口的RCC外設(shè)時(shí)鐘(不打開IO口不能工作);
2.配置IGPO口的模式;
3.配置AFIO,使其選擇我們要用的GPIO口,連接到EXTI;
4.配置EXTI模式,選擇觸發(fā)方式及響應(yīng)方式(中斷or事件);
5.配置NVIC,選擇一個(gè)合適的中斷優(yōu)先級(jí)。
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "mokuaicount.h"
extern int num;
/***************************************************/初始化旋鈕模塊
#include "xuanniu.h" // Device header
#include "stm32f10x.h"
void Xuanniu_init(uint16_t GPIO_Pin)//需要指定端口Pin進(jìn)行模式設(shè)置
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);//使能GPIOA的時(shí)鐘
GPIO_InitTypeDef Xuanniu_InitStruct;
Xuanniu_InitStruct.GPIO_Mode=GPIO_Mode_IPU;//設(shè)置為 上拉輸入 模式
Xuanniu_InitStruct.GPIO_Pin=GPIO_Pin; //外界參數(shù)設(shè)置Pin口
Xuanniu_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; //輸出速度為50MHz,在輸入模式下該設(shè)置沒用
GPIO_Init( GPIOA,&Xuanniu_InitStruct); //以上三個(gè)都要傳入該函數(shù)初始化
}
/***************************************************/配置中斷
//**該模塊由中斷函數(shù)實(shí)現(xiàn),可接入任意輸入模式的模塊實(shí)現(xiàn)計(jì)數(shù)
//**這里引入Key實(shí)現(xiàn)數(shù)據(jù)的減法,LightR實(shí)現(xiàn)加法
#include "stm32f10x.h" // Device header
#include "mokuaicount.h"
#include "Delay.h"
#include "xuanniu.h"
int num;
void Count_interrupt_init(void)
{
//1、2、**步驟一二在模塊內(nèi)已經(jīng)實(shí)現(xiàn)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//AFIO時(shí)鐘需要使能
Xuanniu_init(GPIO_Pin_0|GPIO_Pin_1);
//3**配置AFIO,選擇輸入引腳
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);//Xuanniu旋鈕
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);
//4**配置EXTI寄存器,選擇觸發(fā)方式,這里配置EXTI和GPIO一樣需要定義一個(gè)結(jié)構(gòu)體
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line=EXTI_Line0|EXTI_Line1;
EXTI_InitStruct.EXTI_LineCmd=ENABLE;
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStruct);
//5**配置NVIC,選擇合適的中斷優(yōu)先級(jí) --------每一個(gè)外設(shè)要單獨(dú)配置
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//要先分組,整個(gè)系統(tǒng)NVIC只分配一種模式
//**配置Xuanniu A端
NVIC_InitTypeDef NVIC_InitStruct_Xuanniu;
NVIC_InitStruct_Xuanniu.NVIC_IRQChannel=EXTI0_IRQn;
NVIC_InitStruct_Xuanniu.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct_Xuanniu.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStruct_Xuanniu.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStruct_Xuanniu);
//**配置Xuanniu C端
NVIC_InitStruct_Xuanniu.NVIC_IRQChannel=EXTI1_IRQn;
NVIC_InitStruct_Xuanniu.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct_Xuanniu.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStruct_Xuanniu.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStruct_Xuanniu);
//****所有配置完成
}
//中斷位置隨便放,也不需要聲明
void EXTI0_IRQHandler()//正轉(zhuǎn)觸發(fā)
{
if(EXTI_GetITStatus(EXTI_Line0)==SET)
{
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==0)
{
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1)==1)
{
num++;
}
}
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
void EXTI1_IRQHandler()
{
if(EXTI_GetITStatus(EXTI_Line1)==SET)
{
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1)==0)
{
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==1)
{
num--;
}
}
}
EXTI_ClearITPendingBit(EXTI_Line1);
}
/***************************************************/主函數(shù)
int main(void)
{
OLED_Init();
Count_interrupt_init();
OLED_ShowString(1,1,"Hello,my honey");
OLED_ShowString(2,1,"Hello WangFang");
OLED_ShowString(3,1,"Hello Tomorrow");
while(1)
{
OLED_ShowSignedNum(4,1,num,5);
}
}
/*********************阿布君***********************/
/****************編碼不易,謝謝關(guān)注*****************/
/****************QQ:2062808868********************/
六、TIM定時(shí)中斷
1.結(jié)構(gòu)原理
1.1 介紹
1.2 定時(shí)器種類
不同型號(hào)的開發(fā)板擁有的定時(shí)器資源不一樣
基本定時(shí)器只支持向上計(jì)數(shù)(由0加到重裝載值觸發(fā)中斷后清零)
通用定時(shí)器和高級(jí)定時(shí)器都支持向上計(jì)數(shù)、向下計(jì)數(shù)、中央對(duì)齊三種模式計(jì)數(shù)
1.3 基本定時(shí)器框圖
1.4 通用定時(shí)器框圖
1.5 高級(jí)定時(shí)器框圖
1.6 定時(shí)中斷基本結(jié)構(gòu)
1.7 時(shí)序圖(詳細(xì)解釋)
計(jì)數(shù)流程:選擇時(shí)鐘源-->確定濾波的幾分頻-->確定預(yù)分頻PSC-->確定重裝載值A(chǔ)RR-->溢出觸發(fā)中斷
分頻過程:外部輸入規(guī)律的高低電平脈沖信號(hào),經(jīng)過選擇分頻模式后,信號(hào)轉(zhuǎn)化輸入預(yù)分頻器開始計(jì)數(shù),每到達(dá)預(yù)分頻器設(shè)置的閾值溢出時(shí)就產(chǎn)生一個(gè)脈沖給計(jì)數(shù)器,計(jì)數(shù)器+1,最后當(dāng)計(jì)數(shù)器計(jì)數(shù)值等于自動(dòng)裝載器設(shè)置的閾值時(shí)產(chǎn)生溢出,觸發(fā)中斷,因此在一分頻模式下:
定時(shí)頻率(時(shí)間)=(預(yù)分頻值/初始時(shí)鐘頻率)*預(yù)裝載值
如定時(shí)1s,則1 s=(7200)/72Mhz * 10000? ? ? ? ? ? ? ? ? ? ?(取值范圍 0~65535)
這就像是兩個(gè)定時(shí)器級(jí)聯(lián)一樣,增大了計(jì)數(shù)范圍
最新理解:
已知公式 t=1/f
那么內(nèi)部時(shí)鐘經(jīng)過預(yù)分頻后每記一次的時(shí)間就為:t1=1/(72Mhz/PSC+1)
那么分頻器每隔t1時(shí)間就產(chǎn)生信號(hào)給計(jì)數(shù)器,直到計(jì)數(shù)器經(jīng)過t2=t1*(ARR+1)的時(shí)間或者說累加到等于ARR時(shí),產(chǎn)生中斷同時(shí)計(jì)數(shù)器清零。
所以整個(gè)過程花費(fèi)時(shí)間(每次中斷的間隔時(shí)間)為:t2=1/(72Mhz/PSC+1)*(ARR+1)
比如要計(jì)時(shí) 1s :1 s = 1 / ( 72Mhz / 7200)* 10000
2.定時(shí)器中斷計(jì)數(shù)(代碼)
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "timer2.h"
/***************************************************/定時(shí)器2
#include "stm32f10x.h"
#include "timer2.h"
extern int num;
void timer2_init(void)
{
//**1.打開總的RCC
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因?yàn)槎〞r(shí)器2是通用定時(shí)器,在APB1總線上
//**2.選定定時(shí)器接入的時(shí)鐘
TIM_InternalClockConfig(TIM2);//設(shè)置定時(shí)器2使用內(nèi)部時(shí)鐘,可不寫,上電默認(rèn)
//**3.配置時(shí)基單元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//設(shè)置分頻
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//設(shè)置向上計(jì)數(shù)
TIM_TimeBaseInitStruct.TIM_Period=10000-1;//設(shè)置預(yù)裝載值
TIM_TimeBaseInitStruct.TIM_Prescaler=7200-1;//設(shè)置預(yù)分頻值
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高級(jí)計(jì)數(shù)器功能,重復(fù)計(jì)數(shù)器
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化時(shí)基單元
TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化時(shí)會(huì)產(chǎn)生標(biāo)志位,需要清除
//**4.使能時(shí)基單元的中斷
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
//**5.配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分組
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStruct);
//**6.開始計(jì)數(shù)
TIM_Cmd(TIM2,ENABLE);
}
//**配置中斷函數(shù)
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{
num++;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//一定要清除標(biāo)志位
}
/***************************************************/主函數(shù)
int num;
int main(void)
{
OLED_Init();
timer2_init();
OLED_ShowString(1,1,"Hello,my honey");
// OLED_ShowString(2,1,"Hello WangFang");
// OLED_ShowString(3,1,"Hello Tomorrow");
// OLED_ShowString(4,1,"I miss you");
while(1)
{
OLED_ShowString(2,1,"NUM:");
OLED_ShowNum(2,5,num,5);
OLED_ShowString(3,1,"Prescaler:");
OLED_ShowNum(3,11,TIM_GetPrescaler(TIM2),5);
OLED_ShowString(4,1,"Counter:");
OLED_ShowNum(4,9,TIM_GetCounter(TIM2),5);
}
}
/*********************阿布君***********************/
/****************編碼不易,謝謝關(guān)注*****************/
/****************QQ:2062808868********************/
3.外部時(shí)鐘的定時(shí)器中斷(代碼)
相對(duì)于2的使用內(nèi)部時(shí)鐘,此方法不同之處僅在于使用函數(shù):
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);//第二個(gè)設(shè)置分頻,第三個(gè)設(shè)置觸發(fā)方式,第四個(gè)設(shè)置采樣頻率(濾波器)
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "timer2.h"
/***************************************************/定時(shí)器2
#include "stm32f10x.h"
#include "timer2.h"
extern int num;
void timer2_init(void)
{
//**1.打開總的RCC,要配置GPIO從而傳入外部時(shí)鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因?yàn)槎〞r(shí)器2是通用定時(shí)器,在APB1總線上
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//**2.配置定時(shí)器接入外部時(shí)鐘 同時(shí)配置外部時(shí)鐘輸入的引腳
//TIM_InternalClockConfig(TIM2);//設(shè)置定時(shí)器2使用內(nèi)部時(shí)鐘,可不寫,上電默認(rèn)
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_12;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);//第二個(gè)設(shè)置分頻,第三個(gè)設(shè)置觸發(fā)方式,第四個(gè)設(shè)置采樣頻率(濾波器)
//**3.配置時(shí)基單元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//設(shè)置分頻
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//設(shè)置向上計(jì)數(shù)
// TIM_TimeBaseInitStruct.TIM_Period=10000-1;//設(shè)置預(yù)裝載值 //外部時(shí)鐘的話用不了這么高的頻率
// TIM_TimeBaseInitStruct.TIM_Prescaler=7200-1;//設(shè)置預(yù)分頻值
TIM_TimeBaseInitStruct.TIM_Period=10-1;//設(shè)置預(yù)裝載值
TIM_TimeBaseInitStruct.TIM_Prescaler=2-1;//設(shè)置預(yù)分頻值
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高級(jí)計(jì)數(shù)器功能,重復(fù)計(jì)數(shù)器
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化時(shí)基單元
TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化時(shí)會(huì)產(chǎn)生標(biāo)志位,需要清除
//**4.使能時(shí)基單元的中斷
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
//**5.配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分組
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStruct);
//**6.開始計(jì)數(shù)
TIM_Cmd(TIM2,ENABLE);
}
//**配置中斷函數(shù)
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{
num++;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
/***************************************************/主函數(shù)
int num;
int main(void)
{
OLED_Init();
timer2_init();
OLED_ShowString(1,1,"Hello,my honey");
// OLED_ShowString(2,1,"Hello WangFang");
// OLED_ShowString(3,1,"Hello Tomorrow");
// OLED_ShowString(4,1,"I miss you");
while(1)
{
OLED_ShowString(2,1,"NUM:");
OLED_ShowNum(2,5,num,5);
OLED_ShowString(3,1,"Prescaler:");
OLED_ShowNum(3,11,TIM_GetPrescaler(TIM2),5);
OLED_ShowString(4,1,"Counter:");
OLED_ShowNum(4,9,TIM_GetCounter(TIM2),5);
}
}
/*********************阿布君***********************/
/****************編碼不易,謝謝關(guān)注*****************/
/****************QQ:2062808868********************/
4.TIM(OC)比較輸出(PWM)?。?!
4.1 結(jié)構(gòu)原理介紹(模式)
?8種模式
?TIM_OCMode? ? ? ? ? ? ? ? ? ? ? ? 函數(shù)庫描述? ? ? ? ? ? ? ? ? ? ? ? ? ? ?解釋
TIM_OCMode_Timing? ? ? ?TIM輸出比較? ? ? ? ? ? ? ? ? ?? ?凍結(jié),輸出比較不起作用
TIM_OOCMode_Active? ? ?TIM輸出比較主動(dòng)模式? ? ? ? 當(dāng)比較發(fā)生時(shí),強(qiáng)制輸出高電平
TIM_OCMode_Inactiive?? ?TIM輸出比較非主動(dòng)模式? ? ?當(dāng)比較發(fā)生時(shí),強(qiáng)制輸出低電平
TIM_OCMode_Toggle? ? ? ?TIM輸出比較觸發(fā)模式? ? ? ? 當(dāng)比較發(fā)生時(shí),輸出翻轉(zhuǎn)
TIM_OCMode_PWM1? ? ? ? TIM脈沖寬度調(diào)制模式1? ? ??PWM1
TIM_OCMode_PWM2? ? ? ? TIM脈沖寬度調(diào)制模式2? ? ??PWM2
4.2 輸出設(shè)備(舵機(jī),直流電機(jī))
4.3 代碼配置
4.3.1(呼吸燈、重映射)
先和配置定時(shí)器步驟差不多,只不過最后不需要配置中斷和NVIC,就直接配置CCR
CCR需要先使用TIM_OCStructInit()整體初始化,然后再單獨(dú)配置需要的模式:
????TIM_OCInitTypeDef TIM_OCInitStruct;
?? ?TIM_OCStructInit(&TIM_OCInitStruct);//先整體初始化,防止有些變量未初始化而出錯(cuò)
?? ?TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//配置為PWM1輸出模式
?? ?TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//配置REF為高極性
?? ?TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//配置輸出使能
?? ?TIM_OCInitStruct.TIM_Pulse=100;//配置CCR計(jì)數(shù)器值
?? ?TIM_OC1Init(TIM2,&TIM_OCInitStruct);重映射使用看視頻學(xué)習(xí)
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "PWM.h"
/***************************************************/PWM模塊
#include "stm32f10x.h" // Device header
#include "Delay.h"
void pwm_init(void)
{
//**1.打開總的RCC,要配置GPIO從而傳入外部時(shí)鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因?yàn)槎〞r(shí)器2是通用定時(shí)器,在APB1總線上
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//**2.配置PWM輸出引腳
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//**3.配置時(shí)基單元
//配置為1000KHz,分辨率為1%
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//設(shè)置分頻
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//設(shè)置向上計(jì)數(shù)
TIM_TimeBaseInitStruct.TIM_Period=100-1;//設(shè)置預(yù)裝載值 //外部時(shí)鐘的話用不了這么高的頻率
TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//設(shè)置預(yù)分頻值
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高級(jí)計(jì)數(shù)器功能,重復(fù)計(jì)數(shù)器
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化時(shí)基單元
TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化時(shí)會(huì)產(chǎn)生標(biāo)志位,需要清除
//**4.配置CCR
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct);//先整體初始化,防止有些變量未初始化而出錯(cuò)
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//配置為PWM1輸出模式
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//配置REF為高極性
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//配置輸出使能
TIM_OCInitStruct.TIM_Pulse=100;//配置CCR計(jì)數(shù)器值
TIM_OC1Init(TIM2,&TIM_OCInitStruct);
//5.開始計(jì)數(shù)
TIM_Cmd(TIM2,ENABLE);
}
void LED_run(void)
{
uint16_t num;
for(num=100;num>0;num--)
{
TIM_SetCompare1(TIM2,num);
Delay_ms(10);
}
for(num=0;num<100;num++)
{
TIM_SetCompare1(TIM2,num);
Delay_ms(10);
}
}
/***************************************************/主函數(shù)
int main(void)
{
OLED_Init();
pwm_init();
OLED_ShowString(1,1,"Hello,my honey");
// OLED_ShowString(2,1,"Hello WangFang");
// OLED_ShowString(3,1,"Hello Tomorrow");
// OLED_ShowString(4,1,"I miss you");
while(1)
{
LED_run();
}
}
/*********************阿布君***********************/
/****************編碼不易,謝謝關(guān)注*****************/
/****************QQ:2062808868********************/
4.3.2(旋鈕控制舵機(jī)角度PWM)
旋轉(zhuǎn)旋鈕觸發(fā)中斷從而改變CCR的值(改變占空比)
要注意舵機(jī)的信號(hào)周期為20ms,既50Hz
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "PWM.h"
#include "mokuaicount.h"
/***************************************************/PWM模塊
#include "stm32f10x.h" // Device header
#include "PWM.h"
#include "Delay.h"
void pwm_init(void)
{
//**1.打開總的RCC,要配置GPIO從而傳入外部時(shí)鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因?yàn)槎〞r(shí)器2是通用定時(shí)器,在APB1總線上
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//**2.配置PWM輸出引腳PA0
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//**3.配置時(shí)基單元
//配置為1000KHz,分辨率為1%
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//設(shè)置分頻
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//設(shè)置向上計(jì)數(shù)
TIM_TimeBaseInitStruct.TIM_Period=20000-1;//設(shè)置預(yù)裝載值 //外部時(shí)鐘的話用不了這么高的頻率
TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//設(shè)置預(yù)分頻值
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高級(jí)計(jì)數(shù)器功能,重復(fù)計(jì)數(shù)器
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化時(shí)基單元
TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化時(shí)會(huì)產(chǎn)生標(biāo)志位,需要清除
//**4.配置CCR
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse=0;
TIM_OC1Init(TIM2,&TIM_OCInitStruct);
//5.
//**6.開始計(jì)數(shù)
TIM_Cmd(TIM2,ENABLE);
}
void set_angle(uint16_t angle)
{
TIM_SetCompare1(TIM2,angle);
}
/***************************************************/GPIO初始化
#include "xuanniu.h"
#include "stm32f10x.h"
void Xuanniu_init(uint16_t GPIO_Pin)//需要指定端口Pin進(jìn)行模式設(shè)置
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE);//使能GPIOA的時(shí)鐘
GPIO_InitTypeDef Xuanniu_InitStruct;
Xuanniu_InitStruct.GPIO_Mode=GPIO_Mode_IPU;//設(shè)置為 上拉輸入 模式
Xuanniu_InitStruct.GPIO_Pin=GPIO_Pin; //外界參數(shù)設(shè)置Pin口
Xuanniu_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; //輸出速度為50MHz,在輸入模式下該設(shè)置沒用
GPIO_Init( GPIOB,&Xuanniu_InitStruct); //以上三個(gè)都要傳入該函數(shù)初始化
}
/***************************************************/計(jì)數(shù)模塊
//**該模塊由中斷函數(shù)實(shí)現(xiàn),可接入任意輸入模式的模塊實(shí)現(xiàn)計(jì)數(shù)
//**這里引入Key實(shí)現(xiàn)數(shù)據(jù)的減法,LightR實(shí)現(xiàn)加法
#include "stm32f10x.h" // Device header
#include "mokuaicount.h"
#include "Delay.h"
#include "xuanniu.h"
extern int num;
void Count_interrupt_init(void)
{
//1、2、**步驟一二在模塊內(nèi)已經(jīng)實(shí)現(xiàn)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//AFIO時(shí)鐘需要使能
Xuanniu_init(GPIO_Pin_0|GPIO_Pin_1);
//3**配置AFIO,選擇輸入引腳PB1(C),PB0(A)
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);//Xuanniu旋鈕
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
//4**配置EXTI寄存器,選擇觸發(fā)方式,這里配置EXTI和GPIO一樣需要定義一個(gè)結(jié)構(gòu)體
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line=EXTI_Line0|EXTI_Line1;
EXTI_InitStruct.EXTI_LineCmd=ENABLE;
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStruct);
//5**配置NVIC,選擇合適的中斷優(yōu)先級(jí) --------每一個(gè)外設(shè)要單獨(dú)配置
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//要先分組,整個(gè)系統(tǒng)NVIC只分配一種模式
//**配置Xuanniu A端
NVIC_InitTypeDef NVIC_InitStruct_Xuanniu;
NVIC_InitStruct_Xuanniu.NVIC_IRQChannel=EXTI0_IRQn;
NVIC_InitStruct_Xuanniu.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct_Xuanniu.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStruct_Xuanniu.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStruct_Xuanniu);
//**配置Xuanniu C端
NVIC_InitStruct_Xuanniu.NVIC_IRQChannel=EXTI1_IRQn;
NVIC_InitStruct_Xuanniu.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct_Xuanniu.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStruct_Xuanniu.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStruct_Xuanniu);
//****所有配置完成
}
//中斷位置隨便放,也不需要聲明
void EXTI0_IRQHandler()//正轉(zhuǎn)觸發(fā)
{
if(EXTI_GetITStatus(EXTI_Line0)==SET)
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==0)
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==1)
{
num+=100;
}
}
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
void EXTI1_IRQHandler()
{
if(EXTI_GetITStatus(EXTI_Line1)==SET)
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0)
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==1)
{
num-=100;
}
}
}
EXTI_ClearITPendingBit(EXTI_Line1);
}
/***************************************************/主函數(shù)
int num=1500;
int main(void)
{
OLED_Init();
pwm_init();
Count_interrupt_init();
OLED_ShowString(1,1,"Hello,my baby");
set_angle(num);//默認(rèn)居中
while(1)
{
if(num<=0)
{
num=0;
OLED_ShowString(2,8,"Left Max ");
}
else if(num<1500)
{
OLED_ShowString(2,8,"Left ");
}
else if(num==1500)
{
OLED_ShowString(2,8,"Midel ");
}
else if(num<2500)
{
OLED_ShowString(2,8,"Right ");
}
else if(num>=2500)
{
num=2500;
OLED_ShowString(2,8,"Right Max");
}
OLED_ShowNum(2,1,num,5);
set_angle(num);
}
}
/*********************阿布君***********************/
/****************編碼不易,謝謝關(guān)注*****************/
/****************QQ:2062808868********************/
4.3.3?直流電機(jī)(調(diào)速)
stay待機(jī)控制直接接入高電平3.3v就可以了
in1、in2初始化GPIO(推完輸出模式)然后設(shè)置高低電平即可
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "Motor.h"
/***************************************************/PWM模塊
#include "stm32f10x.h" // Device header
#include "PWM.h"
#include "Delay.h"
void pwm_init(void)
{
//**1.打開總的RCC,要配置GPIO從而傳入外部時(shí)鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因?yàn)槎〞r(shí)器2是通用定時(shí)器,在APB1總線上
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//**2.配置PWM輸出引腳PA0
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//**3.配置時(shí)基單元
//配置為1000KHz,分辨率為1%
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//設(shè)置分頻
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//設(shè)置向上計(jì)數(shù)
TIM_TimeBaseInitStruct.TIM_Period=100-1;//設(shè)置預(yù)裝載值 //外部時(shí)鐘的話用不了這么高的頻率
TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//設(shè)置預(yù)分頻值
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高級(jí)計(jì)數(shù)器功能,重復(fù)計(jì)數(shù)器
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化時(shí)基單元
TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化時(shí)會(huì)產(chǎn)生標(biāo)志位,需要清除
//**4.配置CCR
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse=0;
TIM_OC1Init(TIM2,&TIM_OCInitStruct);
//5.開始計(jì)數(shù)
TIM_Cmd(TIM2,ENABLE);
}
void set_num(uint16_t num)
{
TIM_SetCompare1(TIM2,num);
}
/***************************************************/電機(jī)模塊
#include "stm32f10x.h" // Device header
#include "Motor.h"
#include "PWM.h"
void Motor_init(void)
{
pwm_init();
GPIO_InitTypeDef GPIO_InitStruct;//初始化兩個(gè)方向控制引腳:PA4,PA5
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_Init(GPIOA,&GPIO_InitStruct);
}
void set_speed(int speed)
{
if(speed>=0)
{
set_num(speed);
GPIO_SetBits(GPIOA,GPIO_Pin_4);
GPIO_ResetBits(GPIOA,GPIO_Pin_5);
}
else
{
set_num(-speed);
GPIO_SetBits(GPIOA,GPIO_Pin_5);
GPIO_ResetBits(GPIOA,GPIO_Pin_4);
}
}
/***************************************************/主函數(shù)
int main(void)
{
OLED_Init();
Motor_init();
while(1)
{
set_speed(-100);
}
}
/*********************阿布君***********************/
/****************編碼不易,謝謝關(guān)注*****************/
/****************QQ:2062808868********************/
5.TIM輸入捕獲
5.1 結(jié)構(gòu)原理
利用定時(shí)器模塊計(jì)數(shù),當(dāng)輸入捕獲模塊的邊沿檢測(cè)模塊檢測(cè)到下降沿或上升沿,觸發(fā)獲取CNT的值,每記完一次后CNT清零,獲取到的該周期的CNT值再通過與CNT計(jì)數(shù)頻率即可得到該電平變化周期的時(shí)間T。
由此可見,測(cè)頻法適合測(cè)量高頻,測(cè)周法適合測(cè)量低頻?
?
5.2 代碼配置
5.2.1 單通道測(cè)頻率
這里采用TIM2產(chǎn)生PWM信號(hào)用于測(cè)量
配置TIM3時(shí),也需要配置定時(shí)器時(shí)基模塊使CNT計(jì)數(shù),然后配置IC模塊(通過一個(gè)結(jié)構(gòu)體),再配置從模式的觸發(fā)源和觸發(fā)事件,使能定時(shí)器即可。
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
/***************************************************/PWM模塊
#include "stm32f10x.h" // Device header
void pwm_init(void)
{
//**1.打開總的RCC,要配置GPIO從而傳入外部時(shí)鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因?yàn)槎〞r(shí)器2是通用定時(shí)器,在APB1總線上
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//**2.配置PWM輸出引腳
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//**3.配置時(shí)基單元
//配置為1000KHz,分辨率為1%
TIM_InternalClockConfig(TIM2);//選擇內(nèi)部時(shí)鐘源
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//設(shè)置分頻
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//設(shè)置向上計(jì)數(shù)
TIM_TimeBaseInitStruct.TIM_Period=100-1;//設(shè)置預(yù)裝載值 //外部時(shí)鐘的話用不了這么高的頻率
TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//設(shè)置預(yù)分頻值
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高級(jí)計(jì)數(shù)器功能,重復(fù)計(jì)數(shù)器
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化時(shí)基單元
TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化時(shí)會(huì)產(chǎn)生標(biāo)志位,需要清除
//**4.配置CCR
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct);//先整體初始化,防止有些變量未初始化而出錯(cuò)
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//配置為PWM1輸出模式
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//配置REF為高極性
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//配置輸出使能
TIM_OCInitStruct.TIM_Pulse=0;//配置初始CCR計(jì)數(shù)器值
TIM_OC1Init(TIM2,&TIM_OCInitStruct);
//**5.開始計(jì)數(shù)
TIM_Cmd(TIM2,ENABLE);
}
void set_Zhankongbi(uint16_t num)
{
TIM_SetCompare1(TIM2,num);//通過改變CCR的值,從而改變CCR/CNT占空比
}
void set_PSC(uint16_t num)
{
TIM_PrescalerConfig(TIM2,num,TIM_PSCReloadMode_Immediate);//改變PSC的值
}
/***************************************************/IC輸入捕獲模塊
#include "stm32f10x.h" // Device header
#include "IC.h"
void IC_init(void)
{
//**1.打開總的RCC,要配置GPIO從而傳入外部時(shí)鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//打開TMI3,因?yàn)槎〞r(shí)器2是通用定時(shí)器,在APB1總線上
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//**2.配置PWM輸出引腳PA6
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//**選擇內(nèi)部時(shí)鐘源
TIM_InternalClockConfig(TIM3);
//**3.配置時(shí)基單元
//配置為1MHz
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//設(shè)置分頻
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//設(shè)置向上計(jì)數(shù)
TIM_TimeBaseInitStruct.TIM_Period=65536-1;//設(shè)置預(yù)裝載值 ARR //外部時(shí)鐘的話用不了這么高的頻率
TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//設(shè)置預(yù)分頻值 PSC
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高級(jí)計(jì)數(shù)器功能,重復(fù)計(jì)數(shù)器
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);//初始化時(shí)基單元
TIM_ClearFlag(TIM3,TIM_FLAG_Update);//初始化時(shí)會(huì)產(chǎn)生標(biāo)志位,需要清除
//**4.配置IC模塊
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;//選擇通道一
TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;//選擇上升沿觸發(fā)
TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;//選擇正極性
TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;//選擇一分頻
TIM_ICInitStruct.TIM_ICFilter=0xF;//選擇濾波器的值
TIM_ICInit(TIM3,&TIM_ICInitStruct);
//**5.配置從模式
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
//**6.使能定時(shí)器模塊,開始計(jì)數(shù)
TIM_Cmd(TIM3,ENABLE);
}
uint32_t get_Freq(void)
{
return 1000000/(TIM_GetCapture1(TIM3)+1) ;
}
/***************************************************/主函數(shù)
int main(void)
{
OLED_Init();
pwm_init();
IC_init();
OLED_ShowString(1,1,"Hello,my honey");
set_Zhankongbi(50); //Freq = 72M / (PSC + 1) / 100
set_PSC(720 - 1); //Duty = CCR / 100
while(1)
{
OLED_ShowNum(2,1,get_Freq(),5);
}
}
/*********************阿布君***********************/
/****************編碼不易,謝謝關(guān)注*****************/
/****************QQ:2062808868********************/
5.2.2 PWMI模式同時(shí)測(cè)頻率、占空比
相當(dāng)于開了TI1FP2的通道去實(shí)現(xiàn)讀取占空比
占空比是 CCR2記錄的高電平持續(xù)時(shí)間 除以 CCR1記錄的整個(gè)周期的時(shí)間
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "PWM.h"
#include "IC.h"
/***************************************************/PWM模塊
#include "stm32f10x.h" // Device header
void pwm_init(void)
{
//**1.打開總的RCC,要配置GPIO從而傳入外部時(shí)鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因?yàn)槎〞r(shí)器2是通用定時(shí)器,在APB1總線上
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//**2.配置PWM輸出引腳
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//**3.配置時(shí)基單元
//配置為1000KHz,分辨率為1%
TIM_InternalClockConfig(TIM2);//選擇內(nèi)部時(shí)鐘源
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//設(shè)置分頻
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//設(shè)置向上計(jì)數(shù)
TIM_TimeBaseInitStruct.TIM_Period=100-1;//設(shè)置預(yù)裝載值 //外部時(shí)鐘的話用不了這么高的頻率
TIM_TimeBaseInitStruct.TIM_Prescaler=720-1;//設(shè)置預(yù)分頻值
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高級(jí)計(jì)數(shù)器功能,重復(fù)計(jì)數(shù)器
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化時(shí)基單元
TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化時(shí)會(huì)產(chǎn)生標(biāo)志位,需要清除
//**4.配置CCR
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_OCStructInit(&TIM_OCInitStruct);//先整體初始化,防止有些變量未初始化而出錯(cuò)
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//配置為PWM1輸出模式
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//配置REF為高極性
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//配置輸出使能
TIM_OCInitStruct.TIM_Pulse=0;//配置初始CCR計(jì)數(shù)器值
TIM_OC1Init(TIM2,&TIM_OCInitStruct);
//**5.開始計(jì)數(shù)
TIM_Cmd(TIM2,ENABLE);
}
void set_Zhankongbi(uint16_t num)
{
TIM_SetCompare1(TIM2,num);//通過改變CCR的值,從而改變CCR/CNT占空比
}
void set_PSC(uint16_t num)
{
TIM_PrescalerConfig(TIM2,num,TIM_PSCReloadMode_Immediate);//改變PSC的值
}
/***************************************************/IC輸入捕獲模塊
#include "stm32f10x.h" // Device header
#include "IC.h"
void IC_init(void)
{
//**1.打開總的RCC,要配置GPIO從而傳入外部時(shí)鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//打開TMI3,因?yàn)槎〞r(shí)器2是通用定時(shí)器,在APB1總線上
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//**2.配置PWM輸出引腳PA6
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//**選擇內(nèi)部時(shí)鐘源
TIM_InternalClockConfig(TIM3);
//**3.配置時(shí)基單元
//配置為1MHz
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//設(shè)置分頻
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//設(shè)置向上計(jì)數(shù)
TIM_TimeBaseInitStruct.TIM_Period=65536-1;//設(shè)置預(yù)裝載值 ARR //外部時(shí)鐘的話用不了這么高的頻率
TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;//設(shè)置預(yù)分頻值 PSC
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高級(jí)計(jì)數(shù)器功能,重復(fù)計(jì)數(shù)器
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);//初始化時(shí)基單元
TIM_ClearFlag(TIM3,TIM_FLAG_Update);//初始化時(shí)會(huì)產(chǎn)生標(biāo)志位,需要清除
//**4.配置IC模塊
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;//選擇通道一
TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;//選擇上升沿觸發(fā)
TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;//選擇正極性
TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;//選擇一分頻
TIM_ICInitStruct.TIM_ICFilter=0xF;//選擇濾波器的值
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_PWMIConfig(TIM3,&TIM_ICInitStruct);
//**5.配置從模式
TIM_SelectInputTrigger(TIM3,TIM_TS_TI1FP1);
TIM_SelectSlaveMode(TIM3,TIM_SlaveMode_Reset);
//**6.使能定時(shí)器模塊,開始計(jì)數(shù)
TIM_Cmd(TIM3,ENABLE);
}
uint32_t get_Freq(void)
{
return 1000000/(TIM_GetCapture1(TIM3)+1) ;
}
uint32_t get_Zhankongbi(void)
{
return (TIM_GetCapture2(TIM3)+1)*100/(TIM_GetCapture1(TIM3)+1);
}
/***************************************************/主函數(shù)
int main(void)
{
OLED_Init();
pwm_init();
IC_init();
OLED_ShowString(1,1,"Hello,my honey");
set_Zhankongbi(50); //Freq = 72M / (PSC + 1) / 100
set_PSC(720 - 1); //Duty = CCR / 100
while(1)
{
OLED_ShowNum(2,1,get_Freq(),5);
OLED_ShowNum(3,1,get_Zhankongbi(),3);
}
}
/*********************阿布君***********************/
/****************編碼不易,謝謝關(guān)注*****************/
/****************QQ:2062808868********************/
5.2.3 編碼器接口測(cè)速(簡(jiǎn)介)
通過配置定時(shí)器,占用了IC捕獲模式的兩個(gè)通道,自動(dòng)判斷兩個(gè)腳的波形相位差和邊沿觸發(fā)(一般都是使用T1T2模式,可消除毛刺信號(hào))
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "Bianmaqi.h"
#include "Delay.h"
#include "timer2.h"
/***************************************************/延時(shí)函數(shù)
#include "Delay.h"
#include "stm32f10x.h"
/**
* @brief 微秒級(jí)延時(shí)
* @param xus 延時(shí)時(shí)長(zhǎng),范圍:0~233015
* @retval 無
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //設(shè)置定時(shí)器重裝值
SysTick->VAL = 0x00; //清空當(dāng)前計(jì)數(shù)值
SysTick->CTRL = 0x00000005; //設(shè)置時(shí)鐘源為HCLK,啟動(dòng)定時(shí)器
while(!(SysTick->CTRL & 0x00010000)); //等待計(jì)數(shù)到0
SysTick->CTRL = 0x00000004; //關(guān)閉定時(shí)器
}
/**
* @brief 毫秒級(jí)延時(shí)
* @param xms 延時(shí)時(shí)長(zhǎng),范圍:0~4294967295
* @retval 無
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
/**
* @brief 秒級(jí)延時(shí)
* @param xs 延時(shí)時(shí)長(zhǎng),范圍:0~4294967295
* @retval 無
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
/***************************************************/編碼器
#include "stm32f10x.h" // Device header
#include "Bianmaqi.h"
void Bianmaqi_init(void)
{
//1**使能時(shí)鐘
RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOA,ENABLE);
//2**定義GPIO
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6 |GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//3**初始化時(shí)基單元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_Channel_1|TIM_Channel_2;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_Period=65536-1;
TIM_TimeBaseInitStruct.TIM_Prescaler=1-1;
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
//4**初始化IC模塊(部分)兩個(gè)Pin口
TIM_ICInitTypeDef TIM_ICInitStruct;
TIM_ICStructInit(&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;
TIM_ICInitStruct.TIM_ICFilter=0xF;
// TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;
// TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;
// TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3,&TIM_ICInitStruct);
TIM_ICInitStruct.TIM_Channel=TIM_Channel_2;
TIM_ICInitStruct.TIM_ICFilter=0xF;
// TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;
// TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;
// TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInit(TIM3,&TIM_ICInitStruct);
//5**配置編碼器
TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12,TIM_ICPolarity_Falling,TIM_ICPolarity_Rising);//控制極性
//6.使能定時(shí)器TIM3
TIM_Cmd(TIM3,ENABLE);
}
int16_t get_cnt(void)
{
int16_t temp=0;
temp=TIM_GetCounter(TIM3);
TIM_SetCounter(TIM3,0);
return temp;
}
/***************************************************/定時(shí)器TIM2
#include "stm32f10x.h"
#include "timer2.h"
extern int num;
void timer2_init(void)
{
//**1.打開總的RCC,要配置GPIO從而傳入外部時(shí)鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//因?yàn)槎〞r(shí)器2是通用定時(shí)器,在APB1總線上
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//**2.配置定時(shí)器接入外部時(shí)鐘 同時(shí)配置外部時(shí)鐘輸入的引腳
TIM_InternalClockConfig(TIM2);//設(shè)置定時(shí)器2使用內(nèi)部時(shí)鐘,可不寫,上電默認(rèn)
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_12;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStruct);
//TIM_ETRClockMode2Config(TIM2, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0x00);//第二個(gè)設(shè)置分頻,第三個(gè)設(shè)置觸發(fā)方式,第四個(gè)設(shè)置采樣頻率(濾波器)
//**3.配置時(shí)基單元
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;//設(shè)置分頻
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//設(shè)置向上l計(jì)數(shù)
TIM_TimeBaseInitStruct.TIM_Period=10000-1;//設(shè)置預(yù)裝載值 //外部時(shí)鐘的話用不了這么高的頻率
TIM_TimeBaseInitStruct.TIM_Prescaler=7200-1;//設(shè)置預(yù)分頻值
// TIM_TimeBaseInitStruct.TIM_Period=10-1;//設(shè)置預(yù)裝載值
// TIM_TimeBaseInitStruct.TIM_Prescaler=2-1;//設(shè)置預(yù)分頻值
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;//高級(jí)計(jì)數(shù)器功能,重復(fù)計(jì)數(shù)器
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);//初始化時(shí)基單元
TIM_ClearFlag(TIM2,TIM_FLAG_Update);//初始化時(shí)會(huì)產(chǎn)生標(biāo)志位,需要清除
//**4.使能時(shí)基單元的中斷
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
//**5.配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分組
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStruct);
//**6.開始計(jì)數(shù)
TIM_Cmd(TIM2,ENABLE);
}
/*
//配置中斷函數(shù)
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{
num++;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
*/
/***************************************************/主函數(shù)
int16_t speed=0;
int main(void)
{
timer2_init();
OLED_Init();
Bianmaqi_init();
OLED_ShowString(1,1,"Hello,my honey");
while(1)
{
OLED_ShowSignedNum(2,1,speed,6);
}
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{
speed=get_cnt();
Delay_ms (10);
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
/*********************阿布君***********************/
/****************編碼不易,謝謝關(guān)注*****************/
/****************QQ:2062808868********************/
七、ADC模數(shù)轉(zhuǎn)換
1.結(jié)構(gòu)原理
1.1 介紹
1.2 原理
采樣、抽取、量化、編碼
1.3 ADC結(jié)構(gòu)框圖
1.4 stm32片上資源
1.5 ADC工作的4種模式
1.5.1 單次轉(zhuǎn)換,非掃描模式
1.5.2 連續(xù)轉(zhuǎn)換,非掃描模式
1.5.3 單次轉(zhuǎn)換,掃描模式
1.5.4 連續(xù)轉(zhuǎn)換,掃描模式?
1.6 ADC的觸發(fā)方式(軟件,硬件)
1.7 ADC的數(shù)據(jù)處理、轉(zhuǎn)換時(shí)間、校準(zhǔn)
2.代碼配置
2.1 ADC單通道模式
單次轉(zhuǎn)換、非連續(xù)模式
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "ADC.h"
#include "Delay.h"
/***************************************************/ADC模塊
#include "stm32f10x.h" // Device header
#include "ADC.h"
void ADC_init(void)
{
//1.先使能時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//2.設(shè)置ADC的分頻
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//3.配置GPIO口PA0
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
//4.確定規(guī)則組或注入組的通道
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_28Cycles5);
//5.初始化ADC
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//配置是否連續(xù)觸發(fā)模式
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//選擇數(shù)據(jù)對(duì)齊模式為右對(duì)齊
ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//選擇外界觸發(fā)源
ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//配置是ADC是幾個(gè)同時(shí)工作還是獨(dú)立工作
ADC_InitStruct.ADC_NbrOfChannel=1;//確定要輸入的組的個(gè)數(shù)
ADC_InitStruct.ADC_ScanConvMode=DISABLE;//是否連續(xù)掃描模式
ADC_Init(ADC1, &ADC_InitStruct);
//6.打開ADC
ADC_Cmd(ADC1,ENABLE);
//7.校準(zhǔn)ADC
ADC_ResetCalibration(ADC1);//1.復(fù)位校準(zhǔn)
while(ADC_GetResetCalibrationStatus(ADC1));//2.等待復(fù)位校準(zhǔn)完成
ADC_StartCalibration(ADC1);//3.開始校準(zhǔn)
while(ADC_GetCalibrationStatus(ADC1));//4.等待校準(zhǔn)完成
}
uint16_t get_adcvalue(void)
{
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//觸發(fā)開始ADC讀值
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);//讀取EOC標(biāo)志位,當(dāng)轉(zhuǎn)化讀取完成后退出循環(huán)
return ADC_GetConversionValue(ADC1);//讀取ADC寄存器,自動(dòng)清除EOC標(biāo)志位
}
/***************************************************/延時(shí)函數(shù)
#include "Delay.h"
#include "stm32f10x.h"
/**
* @brief 微秒級(jí)延時(shí)
* @param xus 延時(shí)時(shí)長(zhǎng),范圍:0~233015
* @retval 無
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //設(shè)置定時(shí)器重裝值
SysTick->VAL = 0x00; //清空當(dāng)前計(jì)數(shù)值
SysTick->CTRL = 0x00000005; //設(shè)置時(shí)鐘源為HCLK,啟動(dòng)定時(shí)器
while(!(SysTick->CTRL & 0x00010000)); //等待計(jì)數(shù)到0
SysTick->CTRL = 0x00000004; //關(guān)閉定時(shí)器
}
/**
* @brief 毫秒級(jí)延時(shí)
* @param xms 延時(shí)時(shí)長(zhǎng),范圍:0~4294967295
* @retval 無
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
/**
* @brief 秒級(jí)延時(shí)
* @param xs 延時(shí)時(shí)長(zhǎng),范圍:0~4294967295
* @retval 無
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
/***************************************************/主函數(shù)
uint16_t ADCvalue;//旋鈕值
float Voltage;//轉(zhuǎn)換成電壓值
int main(void)
{
OLED_Init();
ADC_init();
OLED_ShowString(1,1,"Hello,my honey");
OLED_ShowString(2, 1, "ADValue:");
OLED_ShowString(3, 1, "Volatge:0.00V");
while(1)
{
ADCvalue=get_adcvalue();
Voltage = (float)ADCvalue / 4095 * 3.3;
OLED_ShowNum(2, 9, ADCvalue, 4);
OLED_ShowNum(3, 9, Voltage, 1);//這里將電壓值按整數(shù)部分和小數(shù)部分兩部分取出來
OLED_ShowNum(3, 11, (uint16_t)(Voltage * 100) % 100, 2);
Delay_ms(100);;
}
}
/*********************阿布君***********************/
/****************編碼不易,謝謝關(guān)注*****************/
/****************QQ:2062808868********************/
**2.簡(jiǎn)單實(shí)現(xiàn)ADC多通道
每次改變序號(hào)里的通道即可;
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "ADC.h"
#include "Delay.h"
/***************************************************/ADC
#include "stm32f10x.h" // Device header
#include "ADC.h"
void ADC_init(void)
{
//1.先使能時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//2.設(shè)置ADC的分頻
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
//3.配置GPIO口PA0
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
//4.確定規(guī)則組或注入組的通道
// ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_28Cycles5);
//5.初始化ADC
ADC_InitTypeDef ADC_InitStruct;
ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//配置是否連續(xù)觸發(fā)模式
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;//選擇數(shù)據(jù)對(duì)齊模式為右對(duì)齊
ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//選擇外界觸發(fā)源
ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;//配置是ADC是幾個(gè)同時(shí)工作還是獨(dú)立工作
ADC_InitStruct.ADC_NbrOfChannel=1;//確定要輸入的組的個(gè)數(shù)
ADC_InitStruct.ADC_ScanConvMode=DISABLE;//是否連續(xù)掃描模式
ADC_Init(ADC1, &ADC_InitStruct);
//6.打開ADC
ADC_Cmd(ADC1,ENABLE);
//7.校準(zhǔn)ADC
ADC_ResetCalibration(ADC1);//1.復(fù)位校準(zhǔn)
while(ADC_GetResetCalibrationStatus(ADC1));//2.等待復(fù)位校準(zhǔn)完成
ADC_StartCalibration(ADC1);//3.開始校準(zhǔn)
while(ADC_GetCalibrationStatus(ADC1));//4.等待校準(zhǔn)完成
}
uint16_t get_adcvalue(uint8_t ADC_Channel)
{
ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_28Cycles5);
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//觸發(fā)開始ADC讀值
while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);//讀取EOC標(biāo)志位,當(dāng)轉(zhuǎn)化讀取完成后退出循環(huán)
return ADC_GetConversionValue(ADC1);//讀取ADC寄存器,自動(dòng)清除EOC標(biāo)志位
}
/***************************************************/延時(shí)
#include "Delay.h"
#include "stm32f10x.h"
/**
* @brief 微秒級(jí)延時(shí)
* @param xus 延時(shí)時(shí)長(zhǎng),范圍:0~233015
* @retval 無
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //設(shè)置定時(shí)器重裝值
SysTick->VAL = 0x00; //清空當(dāng)前計(jì)數(shù)值
SysTick->CTRL = 0x00000005; //設(shè)置時(shí)鐘源為HCLK,啟動(dòng)定時(shí)器
while(!(SysTick->CTRL & 0x00010000)); //等待計(jì)數(shù)到0
SysTick->CTRL = 0x00000004; //關(guān)閉定時(shí)器
}
/**
* @brief 毫秒級(jí)延時(shí)
* @param xms 延時(shí)時(shí)長(zhǎng),范圍:0~4294967295
* @retval 無
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
/**
* @brief 秒級(jí)延時(shí)
* @param xs 延時(shí)時(shí)長(zhǎng),范圍:0~4294967295
* @retval 無
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}
/***************************************************/主函數(shù)
uint16_t key,light;
int main(void)
{
OLED_Init();
ADC_init();
OLED_ShowString(1,1,"Hello,my honey");
// OLED_ShowString(2,1,"Hello WangFang");
// OLED_ShowString(3,1,"Hello Tomorrow");
// OLED_ShowString(4,1,"I miss you");
while(1)
{
key=get_adcvalue(ADC_Channel_0);
light=get_adcvalue(ADC_Channel_1);
OLED_ShowNum(2,1,key,5);
OLED_ShowNum(3,1,light,5);
}
}
/*********************阿布君***********************/
/****************編碼不易,謝謝關(guān)注*****************/
/****************QQ:2062808868********************/
3.DMA實(shí)現(xiàn)數(shù)據(jù)遷移
**1.結(jié)構(gòu)原理
文章來源:http://www.zghlxwxcb.cn/news/detail-779502.html
待續(xù)
8.USART串口
1.文章來源地址http://www.zghlxwxcb.cn/news/detail-779502.html
到了這里,關(guān)于stm32(F103c8t6)自學(xué)筆記@阿布君的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!