STM32实战五 板载LED显示数据

写到第五章,终于有可以看见的结果了。不过磨刀不误砍柴功。正因为前面的基础,才有今天的成果,而且有一定的实用价值。封装一个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开发过程的常见问题

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章