【RT-Thread Nano】作业4:线程间同步,事件集的使用

实验任务

利用线程间同步-事件集机制,实现当一个ADC通道采样值大于3V 或者另外一个ADC通道采样值小于0.5V时,实现报警功能。ADC通道自由选择。

实验目的

熟悉RT-Thread内核事件集的使用,熟悉STM32 ADC外设多通道采集的使用。

实验环境

1、硬件环境:野火STM32霸道开发板
2、软件环境:RT-Thread Nano 3.1.3,MDK 5.25

实验步骤

1、查看开发板原理图可用的ADC资源,这里选择使用PC1引脚和PC3引脚进行实验。
在这里插入图片描述
2、根据原理图上的引脚去STM32的数据手册获取ADC的通道。
在这里插入图片描述
3、编写驱动程序

bsp_adc.h文件

#ifndef __ADC_H
#define __ADC_H

// 转换通道个数
#define    NOFCHANEL		2

void ADC_Config(void);
void adc_value_update(void *parameter);


#endif /* __ADC_H */

bsp_adc.c文件

#include "config.h"
#include "bsp_adc.h"

__IO uint16_t ADC_ConvertedValue[NOFCHANEL]= {0,0};

static void ADC_GPIO_Config(void)
{
	GPIO_InitTypeDef g;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	
	g.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3;
	g.GPIO_Mode = GPIO_Mode_AIN;
	
	GPIO_Init(GPIOC, &g);
}

static void ADC_Mode_Config(void)
{
	DMA_InitTypeDef d;
	ADC_InitTypeDef a;

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

	/* ADC-DMA初始化 */
	DMA_DeInit(DMA1_Channel1);
	
	d.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC1->DR));
	d.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue;
	d.DMA_DIR = DMA_DIR_PeripheralSRC;
	d.DMA_BufferSize = NOFCHANEL;
	d.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	d.DMA_MemoryInc = DMA_MemoryInc_Enable;
	d.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	d.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	d.DMA_Mode = DMA_Mode_Circular;
	d.DMA_Priority = DMA_Priority_High;
	d.DMA_M2M = DMA_M2M_Disable;
	
	DMA_Init(DMA1_Channel1, &d);
	DMA_Cmd(DMA1_Channel1, ENABLE);
	
	/* ADC初始化 */
	ADC_DeInit(ADC1);
	a.ADC_Mode = ADC_Mode_Independent;
	a.ADC_ScanConvMode = ENABLE;
	a.ADC_ContinuousConvMode = ENABLE;
	a.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	a.ADC_DataAlign = ADC_DataAlign_Right;
	a.ADC_NbrOfChannel = NOFCHANEL;
	ADC_Init(ADC1, &a);
	
	/* 配置ADC时钟PCLK2的8分频,即9MHz */
	RCC_ADCCLKConfig(RCC_PCLK2_Div8); 
	
	/* 配置ADC 通道的转换顺序和采样时间 */
	ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 2, ADC_SampleTime_55Cycles5);
	
	/* 使能ADC的DMA请求,打开ADC */
	ADC_DMACmd(ADC1, ENABLE);
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);					// 初始化ADC 校准寄存器  
	while(ADC_GetResetCalibrationStatus(ADC1));	// 等待校准寄存器初始化完成
	
	ADC_StartCalibration(ADC1);					// ADC开始校准
	while(ADC_GetCalibrationStatus(ADC1));		// 等待校准完成
	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		// 由于没有采用外部触发,所以使用软件触发ADC转换 
}

void ADC_Config(void)
{
	ADC_GPIO_Config();
	ADC_Mode_Config();
}

4、创建ADC报警线程

TaskStruct TaskThreads[] = {
		
		{"iwdg_thread", iwdg_thread_entry, RT_NULL, 512, 15, 10},
		{"led_thread", led_thread_entry, RT_NULL, 512, 15, 10},
		{"usart2_recv_thread", usart2_recv_thread_entry, RT_NULL, 512, 2, 10},
		{"adc_detect_thread", adc_detect_thread_entry, RT_NULL, 512, 5, 10},/* ADC报警线程 */

		/*********************************************************/
		//用户添加线程参数
		//例如:{线程名字,线程入口函数,线程入口函数参数,线程栈大小,线程的优先级,线程时间片},
		
		{" ", RT_NULL, RT_NULL, RT_NULL, RT_NULL, RT_NULL},

};
void adc_detect_thread_entry(void *parameter)
{
	rt_err_t res;
	rt_uint32_t e;
	rt_timer_t adc_timer;
	
	/* 创建软件定时器,用于定时获取ADC数据 */
	adc_timer = rt_timer_create("adc_timer",
								adc_value_update,
								RT_NULL,
								1000,
								RT_TIMER_FLAG_PERIODIC);
	
	if( adc_timer != RT_NULL )
		rt_timer_start(adc_timer);
	else
		rt_kprintf("adc_timer 创建失败!\n");
	
	/* 创建ADC报警事件集 */
	adc_alarm_event = rt_event_create("adc_alarm_event", RT_IPC_FLAG_FIFO);
	
	if( adc_alarm_event == RT_NULL )
		rt_kprintf("adc_alarm_event 创建失败!\n");
	
	while(1)
	{
		res = rt_event_recv(adc_alarm_event,
                       		EVENT_FLAG1 | EVENT_FLAG3,/* 关注EVENT_FLAG1和EVENT_FLAG3事件 */
                       		RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,/* EVENT_FLAG1和EVENT_FLAG3事件逻辑或关系,接受到事件以后清除标记 */
                      		RT_WAITING_FOREVER,
							&e);
		
		if( res == RT_EOK )
		{
			if( e & EVENT_FLAG1 )
				rt_kprintf("警报!PC1引脚电压小于0.5V\n");
			
			if( e & EVENT_FLAG3 )
				rt_kprintf("警报!PC3引脚电压大于3.0V\n");
		
			//BeepOn();
		}
		else
		{
			rt_kprintf("事件集接收发生错误!\n");
		}
	}
}

5、编写定时器周期回调函数

void adc_value_update(void *parameter)
{
	float ADC_ConvertedValueLocal[NOFCHANEL];
	
	rt_interrupt_enter();
	
	ADC_ConvertedValueLocal[0] = (float)ADC_ConvertedValue[0]/4096*3.3;
	ADC_ConvertedValueLocal[1] = (float)ADC_ConvertedValue[1]/4096*3.3;
	
	rt_interrupt_leave();
	
//	rt_kprintf("PC1 = %d \n", ADC_ConvertedValue[0]);
//	rt_kprintf("PC3 = %d \n", ADC_ConvertedValue[1]);
	
	if( ADC_ConvertedValueLocal[0] < 0.5 )//PC1电位器小于0.5V
		rt_event_send(adc_alarm_event, EVENT_FLAG1);
	
	if( ADC_ConvertedValueLocal[1] > 3.0 )//PC3大于3.0V
		rt_event_send(adc_alarm_event, EVENT_FLAG3);
}

测试结果

当PC1电压值小于0.5V或者PC3大于3.0V时,串口调试助手会发出警报。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值