寫到第五章,終於有可以看見的結果了。不過磨刀不誤砍柴功。正因爲前面的基礎,纔有今天的成果,而且有一定的實用價值。封裝一個BoardLED類,主要功能是利用板載LED顯示數據,類似於 Morse code 電報碼,以點亮時間的長短表示二進制數據的0和1,最多4位二進制,十進制15,可以擴展到更多。下面的程序顯示主循環週期時間,單位1us,實際上可以用來顯示設置運行狀態。購買或開發不同的開發板,LED對應的腳號不同,修改程序對應的IO號即可。
BoardLED.h 代碼中用到了前幾章的封裝類,需要前面的原程序,全部做完以後做一個總的封包,上傳到資源庫中。
#ifndef __BOARDLED__
#define __BOARDLED__
extern "C" { // 兼容C,按C語言編譯,Keil5中的包含文件已經加入了C++兼容,不用再加這一段
#pragma diag_remark 368 //消除 warning: #368-D: class "<unnamed>" defines no constructor to initialize the following:
#include "stm32f10x.h"
#pragma diag_default 368 // 恢復368號警告
}
#include "GeneralTimer.h"
#include "IO.h"
class BoardLED : public IO
{
// Construction
public:
BoardLED(GeneralTimer * pTimer);
// Properties
public:
GeneralTimer * m_pTimer; // 定時器
u16 m_nNum; // 要顯示的數
u16 m_nCurrent; // 當前顯示的位
private:
// Methods
public:
void showNumber(void); // 四位二進制形式顯示m_nNum
void showLED(u16 nPin, u8 nOn); // 開關LED
// Overwrite
public:
};
#endif
BoardLED.cpp
/**
******************************************************************************
* @file BoardLED.cpp
* @author Mr. Hu
* @version V1.0.0 STM32F103VET6
* @date 05/20/2019
* @brief 板載LED
* @IO
* PB13 板載LED2,不同的開發板,端口不同,做相應調整
* PE14 板載LED3
* m_t[0] 定時器m_pTimer中的計數1
******************************************************************************
* @remarks
* 從IO類繼承,初始化對應端口
* LED2長短編碼形式顯示二進制數據,短是0,長是1
* 只顯示m_nNum的低四位
*/
/* Includes ------------------------------------------------------------------*/
extern "C" { // 兼容C,按C語言編譯,Keil5中的包含文件已經加入了C++兼容,不用再加這一段
#pragma diag_remark 368 //消除 warning: #368-D: class "<unnamed>" defines no constructor to initialize the following:
#include "stm32f10x_tim.h"
#pragma diag_default 368 // 恢復368號警告
}
#include "GeneralTimer.h" // 通用定時器
#include "BoardLED.h"
/**
* @date 05/20/2019
* @brief 板載LED類
: * IO(GPIOB, GPIO_Pin_13 | GPIO_Pin_14, GPIO_Mode_Out_PP, 1)
* 初始化板載LED對應端口,不同的開發板,端口不同,做相應調整,
* 最後一個參數1表示初始化爲上拉
* @param pTimer,指向通用定時器類對象
* @retval None
*/
BoardLED::BoardLED(GeneralTimer * pTimer)
: IO(GPIOB, GPIO_Pin_13 | GPIO_Pin_14, GPIO_Mode_Out_PP, 1) // 初始化板載LED對應端口,不同的開發板,端口不同,做相應調整,最後一個參數1表示初始化爲上拉
, m_pTimer(pTimer) // 保存定時器
, m_nNum(0) // 要顯示的數,0-15
, m_nCurrent(0x8) // 當前顯示的位,最多4位
{
}
/**
* @date 05/20/2019
* @brief 以二進制形式顯示m_nNum指定的數據
: * LED2點亮時間的長短表示二進制位,短是0,長是1,最大二進制數1111,十進制15。
* @param None
* @retval None
*/
void BoardLED::showNumber(void)
{
u32 & tim = m_pTimer->m_t[0]; // 定時時間
if(tim)
return; // 只有計數到0才顯示
u8 level = GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_13);
if(level) // 當前是高電平,LED不亮
{
GPIO_ResetBits(GPIOB, GPIO_Pin_13); // 設置高電平,點亮
tim = (m_nCurrent & m_nNum) ? 500 : 5; // 當前二進制位是1,顯示500ms,如果二進制位是0顯示200ms秒
m_nCurrent >>= 1; // 移到下一位
}
else // 當前是低電平,LED亮
{
GPIO_SetBits(GPIOB, GPIO_Pin_13); // 設置高電平,熄滅
if(!m_nCurrent) // 數據顯示完畢,暗1.5秒
{
tim = 1500; // 延時1500ms
m_nCurrent = 0x8; // 初始化當前位到最高位
}
else // 二個二進制位中間,暗500ms
tim = 500;
}
}
/**
* @date 05/20/2019
* @brief 板載LED點亮和熄滅
* @param nPin,端口號,PB13 和/或 PB14
* @param nOn,0滅,1亮
* @retval None
*/
void BoardLED::showLED(u16 nPin, u8 nOn)
{
if( nOn )
GPIO_ResetBits(GPIOB, nPin); // 點亮
else
GPIO_SetBits(GPIOB, nPin); // 熄滅
}
Main.h 文件中還沒有實際內容
#ifndef __MAIN__
#define __MAIN__
extern "C" { // 兼容C,按C語言編譯,Keil5中的包含文件已經加入了C++兼容,不用再加這一段
#pragma diag_remark 368 //消除 warning: #368-D: class "<unnamed>" defines no constructor to initialize the following:
#include "stm32f10x.h"
#pragma diag_default 368 // 恢復368號警告
}
#endif
Main.cpp 主入口程序,所列端口有些是以後用的。程序實現兩個功能,一是計算主循環週期,二是設置兩個板載按鍵,按下時LED3點亮,並具有防抖動和抗干擾功能。
/**
******************************************************************************
* @file Main.cpp
* @author Mr. Hu
* @version V1.0.0 STM32F103VET6
* @date 05/18/2019
* @brief 程序入口
* @io
* TIM3 PWM
* TIM4 Encode
* TIM7 通用定時器
* ADC1 ADC
* DAC1
* DAC2
*
* PA0-PA3 ADC
* PA4 DAC1輸出
* PA5 DAC2輸出
* PA6 PWM1
* PA7 PWM2
* PA9 板載串口
* PA10 板載串口
* PA13 板載JLINK佔用
* PA14 板載JLINK佔用
* PA15 板載JLINK佔用
*
* PB1 板載SW2
* PB3 板載JLINK佔用
* PB4 板載JLINK佔用,部分映像的通道1不能用,所以用了沒有得映像
* PB5 PWM
* PB6 編碼器 A
* PB7 編碼器 B
* PB8 板載CAN
* PB9 板載CAN
* PB10 板載RS485
* PB11 板載RS485
* PB13 板載LED2
* PB14 板載LED3
* PB15 板載SW3
*
* PC4 板載RS485
* PC5 板載RS485
******************************************************************************
* @remarks
*
*/
extern "C" { // 兼容C,按C語言編譯,Keil5中的包含文件已經加入了C++兼容,不用再加這一段
#pragma diag_remark 368 //消除 warning: #368-D: class "<unnamed>" defines no constructor to initialize the following:
#include "stm32f10x_tim.h"
#include "stm32f10x_dac.h"
#pragma diag_default 368 // 恢復368號警告
}
#include "stm32f10x_adc.h"
#include "IO.h"
#include "Timer.h"
#include "GeneralTimer.h"
#include "BoardLED.h"
#include "Main.h"
/**
* @date 05/18/2019
* @brief 主入口,主循環
* 如果不正常運行,可能是棧設置不夠 startup_stm32f10x_hd.s Stack_Size EQU 0x600
* @param None
* @retval None
*/
int main(void)
{
SystemInit(); // 配置系統時鐘爲72M
GeneralTimer tim(TIM2); // 通用定時器,實際用TIM7,不佔用IO,但軟件仿真只有1-4,所以選2
BoardLED boardLED( &tim ); // 板載LED
// 板載按鍵,PB1 SW2, PB2 SW3,不同的板子不一樣。
IO key(GPIOB, GPIO_Pin_1 | GPIO_Pin_15, GPIO_Mode_IPU, 2); // GPIOx, nPin, GPIO_Mode_IPU 上拉, 2 輸入時無效
// 使能按鍵濾波
//tim.inb[1].level = 1; // SW2 PB1 上拉
tim.inb[1].enable = 1; // SW2 PB1 使能
//tim.inb[15].level = 1; // SW3 PB15 上拉
tim.inb[15].enable = 1; // SW3 PB15
u32 loopCount = 0; // 主循環計數
while(1)
{
tim.loop(); // 必須放在主循環的第一行,按鍵濾波和上下沿微分。
// LED
// 測試時間
loopCount++;
if( !tim.m_t[2] ) // 定時器2
{
tim.m_t[2] = 1000; // 延時1000ms
boardLED.m_nNum = 1000 * 1000 / loopCount; // 計算循環週期,1000*1000對應週期單位是1us,100*1000是10us,以此類推。
if( boardLED.m_nNum > 0xf )
boardLED.m_nNum = 0xf; // 大於15時,顯示15
loopCount = 0;
}
boardLED.showNumber(); // 顯示四位二進制boardLED.m_nNum,用了m_t[0]
// 開關LED
if( tim.inb[1].down | tim.inb[15].down ) // 兩個板載開關的下降沿
{
boardLED.showLED(GPIO_Pin_14, 1); // 點亮LED3
}
else if( tim.inb[1].up | tim.inb[15].up ) // 兩個板載開關的上升沿
{
boardLED.showLED(GPIO_Pin_14, 0); // 熄滅LED3
}
}
}
把實戰三、四、五的源程序加在一起,編譯下載到單片機中,會看到LED【長短長短】有節奏的顯示二進制1010,說明主循環週期是6us,軟件仿真示波器顯示如下,低電平是點亮。
不同的開發板,數據會不同,如果全部是0或全部是1表示溢出,修改Main.cpp中的量程,【1000*1000對應週期單位是1us,100*1000是10us,以此類推。】,如果都是0,這個數加大,否則減小。這種顯示方式還有一個更好的用途就是顯示錯誤代碼,0表示正常,1-15表示各種異常,當然還可以用作其它用途。
STM32實戰系列源碼,按鍵/定時器/PWM/ADC/DAC/DMA/濾波
STM32實戰一 初識單片機
STM32實戰二 新建工程
STM32實戰三 C++ IO.cpp
STM32實戰四 定時器和按鍵
STM32實戰五 板載LED顯示數據
STM32實戰六 PWM加移相正交
STM32實戰七 數字濾波
STM32實戰八 DAC/ADC
STM32實戰九 編碼器
STM32開發過程的常見問題