写到第五章,终于有可以看见的结果了。不过磨刀不误砍柴功。正因为前面的基础,才有今天的成果,而且有一定的实用价值。封装一个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 " #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 " #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 " #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 " #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实战四 定时器和按键
下一篇:STM32实战六 PWM加移相正交
推荐阅读最新更新时间:2024-11-13 11:03