uCOS 学习笔记(四)基于uCOSiii 的MLX90614ESF红外测温实验

一、基础知识

MLX90614ESF是非接触式红外测温传感器整个系列名称,其中此类型传感器又有多个型号比如AXX、BXX、DXX。不同型号的传感器,所工作的额定电压不同,所测的温度范围不同。而本次实验所使用的为BXX型号。下图所示为参考资料给出的应用电路图。

其中R1和R2是大小为10K的上拉电阻 ,因此传感器的接口为SMBus协议,而SMBus协议与IIC协议类似,所以用了两个电阻对SDA和SCL上拉到3.3V高电平。

uCOS 学习笔记(四)基于uCOSiii 的MLX90614ESF红外测温实验_第1张图片uCOS 学习笔记(四)基于uCOSiii 的MLX90614ESF红外测温实验_第2张图片

 

二、实验部分

本次实验任务的内容如下

① 创建定时器任务,通过定时器回调函数发送信号量至任务A。

② 任务A接收信号量之后驱动传感器采集100次温度数据,取平均值算出数据。

③ 温度是否高于阈值,若高于设定阈值,就向任务B发送内建消息,将当前温度数据传递给任务B,并打印至XCOM。

本次实验使用了UCOSIII的 软件定时器、任务的内建信号量、任务的内建消息队列

三、实验过程

①  在开始任务内创建三个任务

//开始任务函数
void start_task(void *p_arg)
{
	OS_ERR err;
	CPU_SR_ALLOC();
	p_arg = p_arg;

	CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0u
   OSStatTaskCPUUsageInit(&err);  	//统计任务                
#endif
	
#ifdef CPU_CFG_INT_DIS_MEAS_EN		//如果使能了测量中断关闭时间
    CPU_IntDisMeasMaxCurReset();	
#endif
	
#if	OS_CFG_SCHED_ROUND_ROBIN_EN  //当使用时间片轮转的时候
	 //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
#endif		
	
	//创建定时器1
	OSTmrCreate((OS_TMR		*)&tmr1,		//定时器1
                (CPU_CHAR	*)"tmr1",		//定时器名字
                (OS_TICK	 )0,			//20*10=200ms
                (OS_TICK	 )100,          //100*10=1000ms
                (OS_OPT		 )OS_OPT_TMR_PERIODIC, //周期模式
                (OS_TMR_CALLBACK_PTR)tmr1_callback,//定时器1回调函数
                (void	    *)0,			//参数为0
                (OS_ERR	    *)&err);		//返回的错误码	
								
	OS_CRITICAL_ENTER();	//进入临界区			
	
	//创建测温任务
	OSTaskCreate((OS_TCB 	* )&MlxTaskTCB,		//任务控制块
		 (CPU_CHAR	* )"mlx_task", 		//任务名字
         (OS_TASK_PTR )mlx_task, 			//任务函数
         (void		* )0,					//传递给任务函数的参数
         (OS_PRIO	  )MLX_TASK_PRIO,     //任务优先级
         (CPU_STK   * )&MLX_TASK_STK[0],	//任务堆栈基地址
         (CPU_STK_SIZE)MLX_STK_SIZE/10,	//任务堆栈深度限位
         (CPU_STK_SIZE)MLX_STK_SIZE,		//任务堆栈大小
         (OS_MSG_QTY  )0,			//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
         (OS_TICK	  )0,			//当使能时间片轮转时的时间片长度,为0时为默认长度,
         (void   	* )0,					//用户补充的存储区
         (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
         (OS_ERR 	* )&err);				//存放该函数错误时的返回值
				 
	//创建消息接收任务
	OSTaskCreate((OS_TCB 	* )&MSGTaskTCB,		//任务控制块
		 (CPU_CHAR	* )"receive_msg_task", 		//任务名字
         (OS_TASK_PTR )receive_msg_task, 			//任务函数
         (void		* )0,					//传递给任务函数的参数
         (OS_PRIO	  )MSG_TASK_PRIO,     //任务优先级
         (CPU_STK   * )&MSG_TASK_STK[0],	//任务堆栈基地址
         (CPU_STK_SIZE)MSG_STK_SIZE/10,	//任务堆栈深度限位
         (CPU_STK_SIZE)MSG_STK_SIZE,	//任务堆栈大小
         (OS_MSG_QTY  )TASK_Q_NUM,	//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
         (OS_TICK	  )0,		//当使能时间片轮转时的时间片长度,为0时为默认长度,
         (void   	* )0,		//用户补充的存储区
         (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
         (OS_ERR 	* )&err);				//存放该函数错误时的返回值
				 			 											 		 																			 										 
	OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err);	//挂起开始任务			 
	OS_CRITICAL_EXIT();	//进入临界区

}

② 测温任务

void mlx_task(void *p_arg)
{		
	    u8 *pbuf;
        double mxl_val_mean = 0;//100次的平均值
	    float mxl_val[99]={0};//保存100次采集的温度值
	    u8 cnt = 0;
	    OS_ERR err; 
        OSTmrStart(&tmr1,&err);	//开启定时器1	
		while(1)
		{	
	
			//请求信号量			
			OSTaskSemPend(0,OS_OPT_PEND_BLOCKING,0,&err);
		    printf("信号量请求成功\r\n");
			mxl_val_mean = 0;			
			for(cnt = 0;cnt<100;cnt++)//采集100次
			{
				  mxl_val[cnt] = SMBus_ReadTemp();	
				  mxl_val_mean += mxl_val[cnt];//100次累加和	
			}
			mxl_val_mean = mxl_val_mean/100;//取100次的平均值
			printf("mxl_val_mean = %.2f.\r\n",mxl_val_mean);
			if(mxl_val_mean>30)
			{
				printf("温度过高\r\n");
				pbuf = mymalloc(SRAMIN,20);	//申请10个字节
				if(pbuf)
				{	
					printf("内存申请成功\r\n");
					sprintf((char*)pbuf,"high %d",(int)mxl_val_mean);
					//发送消息
					printf("pbuf = %p.\r\n",pbuf);	
				    OSTaskQPost((OS_TCB*	)&MSGTaskTCB,	//向任务Msgdis发送消息
							   (void*		)pbuf,
							   (OS_MSG_SIZE)30,
							   (OS_OPT		)OS_OPT_POST_FIFO,
							   (OS_ERR*	)&err);		
                    printf("消息发送成功\r\n");										 
					if(err != OS_ERR_NONE)
					{
						myfree(SRAMIN,pbuf);	//释放内存
						OSTmrStop(&tmr1,OS_OPT_TMR_NONE,0,&err); //停止定时器1
						tmr1sta = !tmr1sta;		
					}				
				}						
			}
			delay_ms(1000);//延时1秒输出
		}  
}

③ 接收消息任务

void receive_msg_task(void *p_arg)
{		
	        u8 *p;
	        OS_MSG_SIZE size;
	        OS_ERR err;   
		while(1)
		{	
			//请求消息
			printf("正在请求消息\r\n");
			p=OSTaskQPend((OS_TICK		)0,
                         (OS_OPT		)OS_OPT_PEND_BLOCKING,
                         (OS_MSG_SIZE*	)&size,
                         (CPU_TS*		)0,
                         (OS_ERR*      )&err );	
			printf("消息请求成功\r\n");
			//==================================//		
			printf("receive_msg_task接收到的p = %p\r\n",p);			
			//==================================//		
			myfree(SRAMIN,p);	//释放内存
			OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_PERIODIC,&err); //延时1s				
		}  
}

④ 定时器1回调函数

//定时器1的回调函数
void tmr1_callback(void *p_tmr,void *p_arg)
{
	OS_ERR err;
	printf("定时时间到\r\n");
	OSTaskSemPost(&MlxTaskTCB,OS_OPT_POST_NONE,&err);//发送内建信号量	
}

四、实验结果

烧录程序之后,定时器时间到,就发送信号量,任务接收到信号量,就采集温度数据,当温度高于30℃,就发送内建消息,通过接收消息任务将温度数据打印至上位机。

你可能感兴趣的:(UCOSIII)