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 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> Protothreads实现STM32多线程处理 -> 正文阅读

[嵌入式]Protothreads实现STM32多线程处理

在学习嵌入式操作系统之前,我注意到了这个能够实现轻量线程环境的函数库(或者可以说是最最简单的操作系统),于是想动手尝试能不能在STM32工程中浅用一下。

一、将Protothreads加入keil5工程

1.将Protothreads直接复制进工程文件中(源码下载链接Protothreads - download);

2.由于 Protothreads全部由头文件构成,在Keil工程设置中直接include即可。

二、使用Protothreads编写代码

1.仿照Malc编写一个程序:LED1灭一秒亮一秒,同时LED2灭五秒亮五秒。代码如下:

#include <stm32f10x.h>
#include "Led_Key.h"
#include "bsp_exti.h"
#include "bsp_SysTick.h"
#include "bsp_iwdg.h"
#include "bsp_wwdg.h"
#include "bsp_uart.h"
#include "bsp_dma.h"
#include "bsp_adc.h"
#include "bsp_tim2.h"
#include "bsp_rtc.h"
#include <pt.h>//Protothreads头文件,必须包括

static int counter1,counter2;

static int protothread1(struct pt *pt)
{
	PT_BEGIN(pt);//线程开始
	
	while(1)
	{
		PT_WAIT_UNTIL(pt, counter1 == 1);//如果时间满1秒继续执行,否则记录运行点并退出线程1
		GPIOA->ODR ^= GPIO_Pin_1;//灯1状态反转
		counter1 = 0;
	}
	
	PT_END(pt);//线程结束
}

static int protothread2(struct pt *pt)
{
	PT_BEGIN(pt);//线程开始
	
	while(1)
	{
		PT_WAIT_UNTIL(pt, counter2 == 5);//如果时间满5秒继续执行,否则记录运行点并退出线程2
		GPIOA->ODR ^= GPIO_Pin_2;//灯2状态反转
		counter2 = 0;
	}
	
	PT_END(pt);//线程结束
}

static struct pt pt1, pt2;
int main(void)
{	
	PT_INIT(&pt1);//线程1初始化
	PT_INIT(&pt2);//线程2初始化
	
	SysTick_Configuration();
	
	Led_Configuration();

	while(1)
	{
		protothread1(&pt1);//执行线程1
		protothread2(&pt2);//执行线程2
		
		Delay_us(1000000);
		
		counter1++;
		counter2++;
	}
}

?2.编译Keil5,此时提示User\main.c(18): warning: ?#550-D: variable "PT_YIELD_FLAG" was set but never used,不用管,烧录进stm32,观察现象。

?三、Protothreads进阶——信号量

zqnchn讲解了信号量的概念,即“得到了一个信号量,任务继续运行,得不到,一边呆着去”。

要求:板载LED以2秒一周期的速率慢速闪烁。当且仅当串口发来0xaa时,快闪5次。

1.将protothreads文件夹下的文件替换为zqnchn针对Arduino优化后的Protothreads版本(地址:https://toscode.gitee.com/changser/changser_pt_for_arduino);

2.修改pt-timer.h中关于PT_TIMER_DELAY的宏定义,此处笔者采用rtc计时器记录时间(该文件其他宏定义同样可以修改);

#define PT_TIMER_DELAY(pt,time) 				\
		do {															\
			(pt)->t = millis();								\
			PT_WAIT_UNTIL((pt),((pt_timer)(millis()-(pt)->t)>=(time)));\
		}while(0)

修改前?

#define PT_TIMER_DELAY(pt,time) 				\
		do {															\
			(pt)->t = RTC_GetCounter();								\
			PT_WAIT_UNTIL((pt),((pt_timer)(RTC_GetCounter()-(pt)->t)>=(time)));\
		}while(0)

修改后

?3.修改rtc时钟配置(改为rtc每震荡一次经过一毫秒),并编写中断处理函数;

int RTC_Configuration_ms(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE);
	PWR_BackupAccessCmd(ENABLE);
	if(BKP_ReadBackupRegister(BKP_DR1) != 0x1234)
	{
		BKP_DeInit();
		RCC_LSEConfig(RCC_LSE_ON);
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)!=SET)
		{
		}
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
		RCC_RTCCLKCmd(ENABLE);
		RTC_WaitForLastTask();
		RTC_WaitForSynchro();
		RTC_SetPrescaler(32);//(32 + 1) / 32768 ≈ 0.001(s)
		RTC_WaitForLastTask();
		BKP_WriteBackupRegister(BKP_DR1, 0x1234);
		return 0;
	}
	return 1;
}
void USART1_IRQHandler(void)
{
	while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)
	{
		rdata = USART_ReceiveData(USART1);//此处rdata为全局变量,以便被main.c使用
	}
}

4.使用Protothreads编写main.c文件,通过信号量实现要求;

#include <stm32f10x.h>
#include "Led_Key.h"
#include "bsp_exti.h"
#include "bsp_SysTick.h"
#include "bsp_iwdg.h"
#include "bsp_wwdg.h"
#include "bsp_uart.h"
#include "bsp_dma.h"
#include "bsp_adc.h"
#include "bsp_tim2.h"
#include "bsp_rtc.h"

#define PT_USE_TIMER//定时器库
#define PT_USE_SEM//信号量库
#include <pt.h>

static struct pt_sem sem_LED;
unsigned char i;

static int protothread1(struct pt *pt)
{
	PT_BEGIN(pt);//线程开始
	
	while(1)
	{
		PT_SEM_WAIT(pt, &sem_LED); //等待LED信号量可用
		GPIOA->ODR ^= GPIO_Pin_1;//灯1状态反转
		PT_TIMER_DELAY(pt, 1000);//留一秒
		PT_SEM_SIGNAL(pt, &sem_LED);//信号量用完了
		
		PT_YIELD(pt);//让给其他线程(此处很重要,否则会卡在while循环里出不来)
	}
	PT_END(pt);//线程结束
}

static int protothread2(struct pt *pt)
{
	PT_BEGIN(pt);//线程开始
	
	while(1)
	{
		PT_WAIT_UNTIL(pt, rdata == 0xaa);
		
		PT_SEM_WAIT(pt, &sem_LED);//等待LED信号量可用
		
		for(i = 0; i < 5; i++)
		{
			GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_RESET);
			PT_TIMER_DELAY(pt, 200);//留0.2秒	

			GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_SET);
			PT_TIMER_DELAY(pt, 200);//留0.2秒				
		}
		
		rdata = 0;//防止再次while
		
		PT_SEM_SIGNAL(pt, &sem_LED); //信号量用完了
	}
	
	PT_END(pt);//线程结束
}

static struct pt pt1, pt2;
int main(void)
{	
	PT_INIT(&pt1);
	PT_INIT(&pt2);
	PT_SEM_INIT(&sem_LED,1); //初始化信号量为1,即没人用
	
	SysTick_Configuration();
	
	Led_Configuration();
	
	Uart1_Configuration();
	Uart1_NVIC_Init();
	
	RTC_Configuration_ms();//配置RTC时钟,作为定时器库的依托
	
	
	while(1)
	{
		protothread1(&pt1);
		protothread2(&pt2);
	}
}

?5.编译Keil5,烧录进stm32,观察现象。

可以看到, 即使在慢速闪烁(线程1)的过程中,只要接收到串口发来的0xaa,立马转换为快闪(线程2),快闪五次后回到慢闪(线程1),实现了多线程处理。

四、总结

Protothreads已经能为程序设计提供轻量线程环境,解决裸机系统无法处理的多线程问题。后续笔者将尝试接触uC/OS III,正式学习嵌入式操作系统。

参考文章:

1.Arduino教程 ProtoThreads在Arduino中的应用#多任务处理#

2.玩儿大了~给arduino上操作系统了~!

?开发板来源:嵌入式技术公开课

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-06-25 18:19:04  更:2022-06-25 18:19: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 0:31:26-

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