初级会员

- 积分
- 146
- 金钱
- 146
- 注册时间
- 2016-11-4
- 在线时间
- 27 小时
|
本帖最后由 wuhuigps 于 2022-4-18 12:16 编辑
之前发过一篇“授人予鱼之 STM32 多模式按键扫描” 热度有点不够呀!可能是写的不好又或者没有交代清楚代码逻辑及编写思路。
借此 “授人予鱼之 STM32 灵活多变的输出控制” 尝试一下将代码实现过程简单叙述,望能帮助到小伙伴。(本人实不擅长用文字方式表述心中之想法)
GPIO 与 外设之间的输出控制基础就不在此过多探讨了,本文只为实现对外设的灵活控制思路及实现方法流程等进行举例阐述。
前言:项目开发中,单片机对IO外设(灯、锁、各类型传感器、通用外设、外设电源)控制往往都是通过设定相关GPIO引脚Bit_RESET/Bit_SET控制配套功能电路加以实现,但在需要周期性或有时间要求的周期性控制上又会添加配套一堆的逻辑加以控制。特别是刚刚进入嵌入式开发的小伙伴缺少编程思路,一套流程下来不是一堆的delay就是标志位、临时变量、各种周期定时器满天飞。
结合以上本方法需实现的功能思路:
通过一个独立接口函数实现所有OUTput类的外部端口统一设置,实现 输出 Bit_RESET/Bit_SET可控,输出 Bit_RESET/Bit_SET 独立时间可控,输出周期数可控。
例LED: 系统初始化过程中,亮 300ms 灭 200ms,初始化OK后 亮100ms 灭900ms。
例电磁锁:使能开锁命令后,锁通电500ms,能后恢复断电状态。
为方便移植,代码结构根据我上一篇“授人予鱼之 STM32 多模式按键扫描” 进行了统一格式化方便移植
端口初始化部分应用,PIN_ExpOut_LINE_TABLE,PORT_ExpOut_LINE_TABLE,ExpOutPutPin_StateTrigger 数组进行封装。分别为 GPIO pin GPIO port 及 触发有效电平 Bit_RESET/Bit_SET
应用时只需修改以上端口定义及添加 enum ExpOutputInfoTypeList 中的选项即可。
活不多说直接上代码:
- void OutPut_GPIO_Init(void) //GPIO 初始化 这个没什么好讲的了
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- for (INT8U i = 0; i<iOutputInfo_MAX; i++)
- {
- GPIO_InitStructure.GPIO_Pin = PIN_ExpOut_LINE_TABLE[i];
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(PORT_ExpOut_LINE_TABLE[i], &GPIO_InitStructure);
- //取反关闭对应端口
- GPIO_WriteBit(PORT_ExpOut_LINE_TABLE[i], PIN_ExpOut_LINE_TABLE[i], ((ExpOutPutPin_StateTrigger[i] == Bit_SET) ? Bit_RESET : Bit_SET));
- 给需要控制的output赋值初始化
- sExpOUT[i].uOnTime = 0; //开启时间 单位 OutPut_ScanClock
- sExpOUT[i].uOffTime = 0; //关闭时间
- sExpOUT[i].uOnCount = 0; //开启计数
- sExpOUT[i].uOffCount = 0; //关闭计数
- sExpOUT[i].uRepeatTimes =0; //重发次数
- sExpOUT[i].uStateTrigger = ExpOutPutPin_StateTrigger[i];//触发电平状态
- sExpOUT[i].uOutPutLatestStatus = DISABLE; //端口当前状态
- uOutPutLatestStatus 程序运行中需判断对应output状态使用。
- }
- }
- /************************************************
- 函数名称 : SetOutputOnly
- 功 能 : 输出控制
- 参 数 : eType 输出端口
- uiOnTime 开启时间 单位ms OutPut_ScanClock的倍数
- uiOffTime 关闭时间
- ucRepeatTimes 重复次数
- 返 回 值 : 设置成功与否
- 作 者 : wuhui
- *************************************************/
- bool SetOutputOnly(enum ExpOutputInfoTypeList eType, INT16U uiOnTime, INT16U uiOffTime, INT16U ucRepeatTimes) //设定端口输出
- {
- if ( eType >= iOutputInfo_MAX ) return FALSE;
- if ( uiOnTime < OutPut_ScanClock ) return FALSE;
- sExpOUT[eType].uOnTime = uiOnTime;
- sExpOUT[eType].uOffTime = uiOffTime;
- sExpOUT[eType].uOnCount = uiOnTime / OutPut_ScanClock;
- sExpOUT[eType].uOffCount = uiOffTime / OutPut_ScanClock;
- sExpOUT[eType].uRepeatTimes = ucRepeatTimes;
- sExpOUT[eType].uStateTrigger = ExpOutPutPin_StateTrigger[eType];
- GPIO_WriteBit(PORT_ExpOut_LINE_TABLE[eType], PIN_ExpOut_LINE_TABLE[eType], ((sExpOUT[eType].uStateTrigger == Bit_SET) ? Bit_SET : Bit_RESET)); //使能输出
- /*
- 在此先使能对应端口的输出,否则会出现最大OutPut_ScanClock ms真空期(无输出,如用于实时性较高场合前按下面方式操作);
- 使用RTOS 可在此使用信号互斥 发送消息方式解决。消息处理引用ExpOutput_Scan GPIO的输出控制单独独立出来。
- */
- return TRUE;
- }
- void ExpOutput_Scan(void);//输出扫描 可由系统任务周期性调用 无RTOS 定义一个周期与 OutPut_ScanClock 周期相同的TIM调用。
- void ExpOutput_Scan(void) //输出扫描
- {
- for (INT8U i=0; i<iOutputInfo_MAX; i++)
- {
- if( sExpOUT[i].uRepeatTimes == 0 ) continue;
- if( sExpOUT[i].uOnCount >= 1 ) //开时间
- {
- sExpOUT[i].uOnCount --;
- GPIO_WriteBit(PORT_ExpOut_LINE_TABLE[i], PIN_ExpOut_LINE_TABLE[i], ((sExpOUT[i].uStateTrigger == Bit_SET) ? Bit_SET : Bit_RESET)); //使能输出
- }
- else if( sExpOUT[i].uOffCount >= 1 ) //关闭时间
- {
- sExpOUT[i].uOffCount --;
- GPIO_WriteBit(PORT_ExpOut_LINE_TABLE[i], PIN_ExpOut_LINE_TABLE[i], ((sExpOUT[i].uStateTrigger == Bit_SET) ? Bit_RESET : Bit_SET)); //失能输出
- }
-
- if( sExpOUT[i].uOnCount < 1 && sExpOUT[i].uOffCount < 1 ) //开启和关闭都 计时结束了
- {
- if ( sExpOUT[i].uRepeatTimes != OutPut_Hold ) //判断需要执行的次数
- sExpOUT[i].uRepeatTimes --;
- if ( sExpOUT[i].uRepeatTimes > 0 ) //还有没有执行完的循环次数重新赋值给计数器
- {
- sExpOUT[i].uOnCount = sExpOUT[i].uOnTime / OutPut_ScanClock;
- sExpOUT[i].uOffCount = sExpOUT[i].uOffTime / OutPut_ScanClock;
- }
- else
- GPIO_WriteBit(PORT_ExpOut_LINE_TABLE[i], PIN_ExpOut_LINE_TABLE[i], ((sExpOUT[i].uStateTrigger == Bit_SET) ? Bit_RESET : Bit_SET)); //失能输出
- }
- if( GetOutputStateOnly((enum ExpOutputInfoTypeList)i) == (INT8U)ExpOutPutPin_StateTrigger[i]) //获取输出端口状态
- sExpOUT[i].uOutPutLatestStatus = ENABLE;
- else
- sExpOUT[i].uOutPutLatestStatus = DISABLE;
- }
- }
复制代码
由高优先级任务或定时器按 OutPut_ScanClock 20ms 周期性调用。
在ExpOutput_Scan中进行相关端口的 ExpOutIndicationDataType 参数传入判断。
先判读 需执行的周期数,再判断需要开启的时间和关闭时间。
开启关闭时间为0后再判断剩下需要执行的周期数,如果不为OutPut_Hold持续输出。则递减周期数重新赋值需要开启和关闭的时间。
bool SetOutputOnly(enum ExpOutputInfoTypeList eType, INT16U uiOnTime, INT16U uiOffTime, INT16U ucRepeatTimes) 设定对应OUTput端口。
例LED: 系统初始化过程中,亮 300ms 灭 200ms,初始化OK后 亮100ms 灭900ms。
初始化过程中 SetOutputOnly(iOutputInfo_LED0,300, 200, OutPut_Hold);
初始化OK SetOutputOnly(iOutputInfo_LED0,100, 900, OutPut_Hold);
例电磁锁:使能开锁命令后,锁通电500ms,能后恢复断电状态。
SetOutputOnly(iOutputInfo_LOCK1,500, 0, 1);
以下代码压缩包
Output.rar
(2.65 KB, 下载次数: 2)
|
|