STM32F103用STM32CubeMX更换底层,并以时间片轮换时间调度的系统,编写信号指示灯

前言:

        信号指示灯,最好不要用单个的常量或常灭的形式指示,因为有可能是程序BUG造成程序宕机。

        本篇用四个LED指示灯,LED1、LED2、LED3、LED4,如图

        其中,LED1的作用是检测系统是否工作,以1s为周期的呼吸灯,当不闪烁的时候,说明系统故障。

        其余三个指示灯,用于反应系统的事件。每个LED灯能反映5个事件,事件1:常亮,事件2:以200ms的周期闪烁,事件3:以500ms周期闪烁,事件4:以1s的周期闪烁,事件5:常灭。

        用结构体命名,为sigLEDxx.light、sigLEDxx.l200ms、sigLEDxx.l500ms、sigLEDxx.l1s、sigLEDxx.ns   。其中xx是第几个灯的意思,比如第二个  sigLED02   。 后面的是周期时间。

正文:

        打开上次建立的STM32CubeMX文件

1、配置4个LED灯的底层,看原理图

全是底边驱动,可以开漏输出,IO为低电平灯亮,反之灯灭。其中LED1--PB8、LED2--PB15、LED3--PA12、LED4--PB11。

1.2、配置STM32CubeMX,先单击第一处,再单击第二处

1.3、同样操作,PB15、PA12、PB11

 

1.3、把PB8、PB15、PA12、PB11配置成和下图相同,初始LED灯都是灭的

 1.4、一键跟新代码,并打开编译一下,无错误、无警告

 2、修改上次代码-由于上次代码 “  App_task();  ”放错位置,导致被系统删掉,重新添加

main.c文件的main()函数的死循环中,丢失后的代码,如下

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	if(RxEndFlag == 1)  //接收完成标志
	{
		for(unsigned char i=0;i<RxLen;i++)
		{
			TxBuffTest[i]=RxBuff[i];
		}
		PMJD_UART1_DMA_Send(TxBuffTest, RxLen);//发送接收到的数据
		memset(RxBuff,0,RxLen);//清除接收到的数据
		RxLen = 0;//清除计数
		RxEndFlag = 0;//清除接收结束标志位
	}
  }
  /* USER CODE END 3 */

 修改补充,代码如下

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	App_task();
	if(RxEndFlag == 1)  //接收完成标志
	{
		for(unsigned char i=0;i<RxLen;i++)
		{
			TxBuffTest[i]=RxBuff[i];
		}
		PMJD_UART1_DMA_Send(TxBuffTest, RxLen);//发送接收到的数据
		memset(RxBuff,0,RxLen);//清除接收到的数据
		RxLen = 0;//清除计数
		RxEndFlag = 0;//清除接收结束标志位
	}
  }
  /* USER CODE END 3 */

3、在“APP”的目录下,新建一个文件夹“BSP”,在新建的文件夹里新建新的文件夹“Inc”和“Src”,把“BSP”添加到结构树中,把“BSP”下的“Inc”文件夹添加到“魔法棒” 头文件目录中,同“APP”操作

 

 4、建立“BspSigLED.c”文件并保存在“BSP”文件下的“Src”文件中,让后把文件“BspSigLED.c”添加在结构树的“BSP”目录下,建立“BspSigLED.h”文件并保存在“BSP”文件下的“Inc”文件中。同建立“AppTask”文件的操作

 5、“BspSigLED.h”的代码

#ifndef _BSPSIGLED_H_
#define _BSPSIGLED_H_

#include "AppTask.h"

typedef struct
{
	unsigned char 		LED01;	// 1-常亮; 2-T=200ms闪烁; 3-T=500ms闪烁; 4-T=1s闪烁; 0-常灭
	unsigned char 		LED02;	// 1-常亮; 2-T=200ms闪烁; 3-T=500ms闪烁; 4-T=1s闪烁; 0-常灭
	unsigned char		LED03;	// 1-常亮; 2-T=200ms闪烁; 3-T=500ms闪烁; 4-T=1s闪烁; 0-常灭 
	unsigned char    	LED04;	// 1-常亮; 2-T=200ms闪烁; 3-T=500ms闪烁; 4-T=1s闪烁; 0-常灭
}sigLEDk;

void SigLED(void);

#endif

 6、“BspSigLED.c”的代码,由于对时钟要求很低,所以用任务执行间隔事件充当时钟

#include "BspSigLED.h"

extern sigLEDk sigLED;

//灯光闪烁,指示系统事件运行,每隔50ms函数运行一次
void SigLED(void)
{
	// 1-常亮; 2-T=200ms闪烁; 3-T=500ms闪烁; 4-T=1s闪烁; 0-常灭
	static unsigned char time100ms,time250ms,time500ms;
	time100ms++;
	time250ms++;
	time500ms++;
	
	if(sigLED.LED01 == 1)//1
	{
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);//IO输出低电平
	}
	else if(sigLED.LED01 == 0)
	{
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);//IO输出高电平
	}
	if(sigLED.LED02 == 1)//2
	{
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_RESET);
	}
	else if(sigLED.LED02 == 0)
	{
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, GPIO_PIN_SET);
	}
		if(sigLED.LED03 == 1)//3
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);
	}
	else if(sigLED.LED03 == 0)
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_SET);
	}
	if(sigLED.LED04 == 1)//4
	{
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET);
	}
	else if(sigLED.LED04 == 0)
	{
		HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET);
	}
	
	if(time100ms>=2)//半个周期为100ms,T=200ms
	{
		time100ms=0;
		if(sigLED.LED01 == 2)
		{
			HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);//IO输出电平-高低电平反转
		}
		if(sigLED.LED02 == 2)
		{
			HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_15);
		}
		if(sigLED.LED03 == 2)
		{
			HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_12);
		}
		if(sigLED.LED04 == 2)
		{
			HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_11);
		}
	}
	if(time250ms>=5)//半个周期为250ms,T=500ms
	{
		time250ms=0;
		if(sigLED.LED01 == 3)
		{
			HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
		}
		if(sigLED.LED02 == 3)
		{
			HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_15);
		}
		if(sigLED.LED03 == 3)
		{
			HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_12);
		}
		if(sigLED.LED04 == 3)
		{
			HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_11);
		}
	}
	if(time500ms>=10)//半个周期为500ms,T=1s
	{
		time500ms=0;
		if(sigLED.LED01 == 4)
		{
			HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_8);
		}
		if(sigLED.LED02 == 4)
		{
			HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_15);
		}
		if(sigLED.LED03 == 4)
		{
			HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_12);
		}
		if(sigLED.LED04 == 4)
		{
			HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_11);
		}
	}
}

7、在“AppTask.h”的头文件中添加上  “  #include "BspSigLED.h"  ”头文件

#include "main.h"
#include "stdio.h"
#include "stdbool.h"
#include "adc.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"
#include "BspSigLED.h"

8、在“AppTask.c”的任务注册表中添加,该任务,非实时性任务,无需上电执行,每隔50ms执行一次

//任务注册表
static TaskCtrl_t	TaskCtrl[] = //执行优先级程度 从上到下依次逐渐,第一个优先级最高,所有的任务函数都不能打断其它的任务函数
{
	/*	【实时任务】	【上电立即运行】	【初始counter】			【任务周期ms】				【任务指针】*/  //时间调度最好是cycle_task的整数倍
	{	0,  				0, 				0/cycle_task,			500/cycle_task,				taskTest},
	{	0,					0,				0/cycle_task,			50/cycle_task,				SigLED},
};

9、整理一下,之前的代码

        之前测试串口信息-接收到之后,再发出去。也放在时间片轮换调度系统中,实时性任务

原代码在main.c文件的main()函数的死循环中,如下,移植(原来位置不保留)到“AppTask.c”文件,新建一个测试函数

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	App_task();
	if(RxEndFlag == 1)  //接收完成标志
	{
		for(unsigned char i=0;i<RxLen;i++)
		{
			TxBuffTest[i]=RxBuff[i];
		}
		PMJD_UART1_DMA_Send(TxBuffTest, RxLen);//发送接收到的数据
		memset(RxBuff,0,RxLen);//清除接收到的数据
		RxLen = 0;//清除计数
		RxEndFlag = 0;//清除接收结束标志位
	}
  }
  /* USER CODE END 3 */

移植后

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	App_task();
  }
  /* USER CODE END 3 */

10、“AppTask.c”文件下添加代码,如下

//实时性任务
void taskTestTime(void)
{
	unsigned char TxBuffTest[BUFFER_SIZE];
	if(RxEndFlag == 1)  //接收完成标志
	{
		for(unsigned char i=0;i<RxLen;i++)
		{
			TxBuffTest[i]=RxBuff[i];
		}
		PMJD_UART1_DMA_Send(TxBuffTest, RxLen);//发送接收到的数据
		memset(RxBuff,0,RxLen);//清除接收到的数据
		RxLen = 0;//清除计数
		RxEndFlag = 0;//清除接收结束标志位
	}
}

11、“AppTask.h”文件下给“  void taskTestTime(void);  ”函数声明,如下

void App_task(void);
void taskTest(void);
void taskTestTime(void);

12、建立初始化函数,此函数,仅上电的时候运行一次

12.1、“AppTask.c”文件下添加代码,如下

void AppInit(void)
{
	
}

12.2、“AppTask.h”文件下给“  void AppTask(void);  ”函数声明,如下

void App_task(void);
void taskTest(void);
void taskTestTime(void);
void AppInit(void);

12.3、在main.c文件下的main()函数中死循环上面的位置添加函数  AppInit();//用于初始化函数

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&ADC,10); 
  AppInit();//用于初始化函数
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)

13、在初始化的函数 “  AppInit();  ”里,输入指示灯的信号,检查指示灯的响应


sigLEDk sigLED;

void AppInit(void)
{
	sigLED.LED01=1;
	sigLED.LED02=2;
	sigLED.LED03=3;
	sigLED.LED04=4;
}

14、“AppTask.c”的代码为

#include "AppTask.h"

//任务注册表
static TaskCtrl_t	TaskCtrl[] = //执行优先级程度 从上到下依次逐渐,第一个优先级最高,所有的任务函数都不能打断其它的任务函数
{
	/*	【实时任务】	【上电立即运行】	【初始counter】			【任务周期ms】				【任务指针】*/  //时间调度最好是cycle_task的整数倍
	{   1,                  0,              0,                      100/cycle_task,           taskTestTime},
	{	0,  				0, 				0/cycle_task,			500/cycle_task,				taskTest},
	{	0,					0,				0/cycle_task,			50/cycle_task,				SigLED},
};

#define TASK_MAX_NUM	(sizeof(TaskCtrl)/sizeof(TaskCtrl[0])) //自动生成任务调度的数量给 TASK_MAX_NUM
	
void App_task(void)
{
	volatile unsigned char i_task, j_task;
	static unsigned int timen_task;
	if(timen - timen_task >= cycle_task)//每间隔 cycle_task ms 执行一次
	{
		timen_task = timen;//和上面if括号的那句共同构成 每隔cycle_task个定时周期更新一次任务等待时长
		for(i_task = 0; i_task < TASK_MAX_NUM; i_task++)//把所有的任务检测一边
		{
			if((TaskCtrl[i_task].Task_Counter > 0)&&(TaskCtrl[i_task].Task_RealTime == 0))//用于防止初始计数值为零,自减溢出
				TaskCtrl[i_task].Task_Counter--;
			if((TaskCtrl[i_task].Task_Counter == 0)&&(TaskCtrl[i_task].Task_RealTime == 0))//自减为零的时候,认为该任务可以执行
			{
				TaskCtrl[i_task].Task_Running = true;//认为为可执行任务
				TaskCtrl[i_task].Task_Counter = TaskCtrl[i_task].Task_PeriodTime;//更新计时周期
			}
		}
	}
	for(j_task = 0; j_task < TASK_MAX_NUM; j_task++)//排队执行可执行函数
	{// 任务调用
		if(TaskCtrl[j_task].Task_Running || TaskCtrl[j_task].Task_RealTime)
		{
			TaskCtrl[j_task].TaskHook();//执行函数
			TaskCtrl[j_task].Task_Running = false;//执行结束
		}
	}
	
}

sigLEDk sigLED;

void AppInit(void)
{
	sigLED.LED01=1;
	sigLED.LED02=2;
	sigLED.LED03=3;
	sigLED.LED04=4;
}

void taskTest(void)
{
	static unsigned int time;
	for(unsigned char i=0;i<10;i++)
		TxBuff[i]=0x00+i;
	TxBuff[10]=0x0D;
	TxBuff[11]=0x0A;
	if((TxEndFlag == 0)&(timen - time >= 1000))
	{
		time = timen;
		PMJD_UART1_DMA_Send(TxBuff,12);
	}
}

//实时性任务
void taskTestTime(void)
{
	unsigned char TxBuffTest[BUFFER_SIZE];
	if(RxEndFlag == 1)  //接收完成标志
	{
		for(unsigned char i=0;i<RxLen;i++)
		{
			TxBuffTest[i]=RxBuff[i];
		}
		PMJD_UART1_DMA_Send(TxBuffTest, RxLen);//发送接收到的数据
		memset(RxBuff,0,RxLen);//清除接收到的数据
		RxLen = 0;//清除计数
		RxEndFlag = 0;//清除接收结束标志位
	}
}

15、“AppTask.h”的代码为

#ifndef _APPTASK_H_
#define _APPTASK_H_

#include "main.h"
#include "stdio.h"
#include "stdbool.h"
#include "adc.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"
#include "BspSigLED.h"

#define cycle_task 1  //每cycle_task个timen周期 轮换一次

typedef struct
{
	bool 				Task_RealTime;			// 任务是否需要实时调用
	bool 				Task_Running;			// 任务运行标记
	unsigned short		Task_Counter;			// 任务计数器
	unsigned short    	Task_PeriodTime;		// 任务运行周期
	void 				(*TaskHook)(void);		// 任务函数指针
}TaskCtrl_t;

void App_task(void);
void taskTest(void);
void taskTestTime(void);
void AppInit(void);

#endif

16、烧入程序  1-常亮; 2-T=200ms闪烁; 3-T=500ms闪烁; 4-T=1s闪烁; 0-常灭 ,观察闪烁周期

经过验证,和响应和预设状态相同

1-常亮; 2-T=200ms闪烁; 3-T=500ms闪烁; 4-T=1s闪烁;

灯光 成功

17、验证串口收发功能正常  成功

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逐梦之程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值