IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32F103用STM32CubeMX更换底层,并以时间片轮换时间调度的系统,编写信号指示灯 -> 正文阅读

[嵌入式]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、验证串口收发功能正常? 成功

?

?

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-10-23 12:39:15  更:2021-10-23 12:40:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:54:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码