第十二届 蓝桥杯 嵌入式设计与开发项目 决赛

本文介绍了基于STM32CubeMX的ADC配置、输入捕获和串口通信的实现,涉及按键功能、串口数据处理和定时器输入捕获回调函数的详细代码。通过按键切换显示模式,更新参数或数据显示,并通过串口发送和接收数据,实现设备的远程控制和数据查询。此外,还展示了如何利用输入捕获计算频率和处理超时情况。
摘要由CSDN通过智能技术生成

赛题

在这里插入图片描述

CubeMX配置

ADC

在这里插入图片描述
在这里插入图片描述

输入捕获

在这里插入图片描述
在这里插入图片描述

串口

在这里插入图片描述
在这里插入图片描述

部分代码

按键功能

void KEY_function(void)
{
	uint8_t key;
	
	key=KEY_scan();
	
	if(key)
	{
		if(key==1)	//界面切换
		{
			FLAG.display_mode=!FLAG.display_mode;
			
			LCD_Clear(Black);
			if(FLAG.display_mode)	//参数设置界面&
			{
				FLAG.display_Refresh|=LCD_Line1|LCD_Line2|LCD_Line3|LCD_Line4;
				sprintf((char *)LCD_Line_buf[1],"        PARA        ");
				sprintf((char *)LCD_Line_buf[2],"   Pax:%2d  ",DATA.Pax);
				sprintf((char *)LCD_Line_buf[3],"   Pbx:%2d  ",DATA.Pbx);
				sprintf((char *)LCD_Line_buf[4],"   Pf:%-5d  ",DATA.Pf);
			}
			else					//数据显示界面
			{
				FLAG.display_Refresh|=LCD_Line1|LCD_Line2|LCD_Line3|LCD_Line4|LCD_Line6|LCD_Line7|LCD_Line8;
				sprintf((char *)LCD_Line_buf[1],"        DATA        ");
				sprintf((char *)LCD_Line_buf[2],"   a:%-4.1f  ",DATA.a);
				sprintf((char *)LCD_Line_buf[3],"   b:%-3.1f  ",DATA.b);
				sprintf((char *)LCD_Line_buf[4],"   f:%-dHz  ",DATA.f);			
			}
		}
		else if(key==2)
		{
			if(FLAG.display_mode)	//仅在参数设置界面下生效
			{
				if(DATA.Pax+=10,DATA.Pax>60) DATA.Pax=10;
				if(DATA.Pbx+=10,DATA.Pbx>60) DATA.Pbx=10;
				
				if(DATA.ax>DATA.Pax) led_state&=(~LD1);
				else 				 led_state|=LD1;					

				if(DATA.bx>DATA.Pbx) led_state&=(~LD2);
				else 				 led_state|=LD2;	
				
				sprintf((char *)LCD_Line_buf[2],"   Pax:%2d  ",DATA.Pax);
				sprintf((char *)LCD_Line_buf[3],"   Pbx:%2d  ",DATA.Pbx);
				FLAG.display_Refresh|=LCD_Line2|LCD_Line3;				
			}
		}
		else if(key==3)
		{
			if(FLAG.display_mode)	//仅在参数设置界面下生效
			{
				if(DATA.Pf+=1000,DATA.Pf>10000)	DATA.Pf=1000;
				sprintf((char *)LCD_Line_buf[4],"   Pf:%-5d  ",DATA.Pf);
				FLAG.display_Refresh|=LCD_Line4;
			}
			else	//在数据显示界面下,切换触发模式 
			{
				DATA.mode=(DATA.mode=='A')?'B':'A';
				
				if(DATA.mode=='A') led_state&=(~LD4);
				else led_state|=LD4;
				
				LCD_Line_buf[8][8]=DATA.mode;
				FLAG.display_Refresh|=LCD_Line8;
				FLAG.ADC_state=0;
			}
		}
		else if(key==4)
		{
			if(DATA.mode=='A')	//仅在模式A(按键触发)下有效
			{
				FLAG.measure_pwm|=0x03;	//触发一次角度数据刷新
			}
		}
	}
}

串口功能

u8 buf[35]={0};
	
//返回值: 0-数据错误
//		   1-数据正确
u8  USART_Data_handle(void)
{

	memset(buf,0,35);
	
	if(UART2_len>3)	return 0;
	
	if( (UART2_len==2) && (UART2_buf[1]=='?') )	//查询当前角度数据
	{
		if(UART2_buf[0]=='a')
		{
			sprintf((char *)buf,"a:%-4.1f",DATA.a);
		}
		else if(UART2_buf[0]=='b')
		{
			sprintf((char *)buf,"b:%-4.1f",DATA.b);
		}
		else return 0;
	}
	else if( (UART2_len==3) && (UART2_buf[2]=='?') )//查询历史角度数据
	{
		if(UART2_buf[0]=='q')	//数据排列输出
		{
			if(UART2_buf[1]=='a')
			{			
				ShellSort(DATA.a_buf_Size,5);
				sprintf((char *)buf,"qa:%-4.1f-%-4.1f-%-4.1f-%-4.1f-%-4.1f",
					DATA.a_buf_Size[0],DATA.a_buf_Size[1],DATA.a_buf_Size[2],DATA.a_buf_Size[3],DATA.a_buf_Size[4]);				
			}
			else if(UART2_buf[1]=='b')
			{
				ShellSort(DATA.b_buf_Size,5);
				sprintf((char *)buf,"qb:%-4.1f-%-4.1f-%-4.1f-%-4.1f-%-4.1f",
					DATA.b_buf_Size[0],DATA.b_buf_Size[1],DATA.b_buf_Size[2],DATA.b_buf_Size[3],DATA.b_buf_Size[4]);					
			}
			else return 0;
		}
		else if(UART2_buf[0]==UART2_buf[1])	//时间排列输出
		{
			if(UART2_buf[0]=='a')
			{
				sprintf((char *)buf,"aa:%-4.1f-%-4.1f-%-4.1f-%-4.1f-%-4.1f",
					DATA.a_buf[0],DATA.a_buf[1],DATA.a_buf[2],DATA.a_buf[3],DATA.a_buf[4]);
			}
			else if(UART2_buf[0]=='b')
			{
				sprintf((char *)buf,"bb:%-4.1f-%-4.1f-%-4.1f-%-4.1f-%-4.1f",
					DATA.b_buf[0],DATA.b_buf[1],DATA.b_buf[2],DATA.b_buf[3],DATA.b_buf[4]);				
			}
			else return 0;
		}
		else return 0;
	}
	else return 0;
	
	HAL_UART_Transmit_DMA(&huart1,buf,35);
	return 1;
}

void USART_function(void)
{	
	if(UART2_over_flag)
	{
		UART2_over_flag=0;
 
		if(!USART_Data_handle())	//串口数据处理
		{
			HAL_UART_Transmit_DMA(&huart1,"error",5);		
		}
		HAL_UART_Receive_DMA(&huart1,UART2_buf,UART2_LEN_MAX);	//重新使能串口DMA接收
	}
}

输入捕获功能

void TIM_IN_function(void)
{
	u8 a;
	float data;
	static u8 TIM_IN_flag=0;
	
	//TIM2 CH2
	if(!TIME_TASK.TIM_IN[0])
	{
		if(TIM2_IN.flag[1]==0)
		{
			TIM2_IN.flag[1]++;
			TIM2->CNT=0;
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_RISING);
			HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_2);

			TIME_TASK.OVERTIME[0]=1000;				
		}
		else if(TIM2_IN.flag[1]==3)
		{
			TIM_IN_flag++;
			TIM2_IN.flag[1]=0;
			
			TIM2_IN.FRQ[1]=TIM2_IN.TIME_TWO[1]-TIM2_IN.TIME_OEN[1];
			if(TIM2_IN.FRQ[1]) TIM2_IN.FRQ[1]=1000000/TIM2_IN.FRQ[1];
			
			DATA.f=TIM2_IN.FRQ[1];
	
			if(DATA.f>DATA.Pf)	led_state&=(~LD3);
			else 				led_state|=LD3;
			
			if(FLAG.display_mode==0)
			{
				sprintf((char *)LCD_Line_buf[4],"   f:%dHz  ",DATA.f);
				FLAG.display_Refresh|=LCD_Line4;			
			}
			
			TIME_TASK.TIM_IN[0]=TIM_IN_TIME;
		}
		else
		{				
			if(!TIME_TASK.OVERTIME[0])
			{
				HAL_TIM_IC_Stop_IT(&htim2,TIM_CHANNEL_2);
				TIM2_IN.TIME_OEN[1]=0;
				TIM2_IN.TIME_TWO[1]=0;
				TIM2_IN.flag[1]=3;
			}
		}
	}
	//TIM3 CH1/2	
	for(a=0;a<2;a++)
	{
		if(FLAG.measure_pwm&(0x01<<a))
		{
			if(TIM3_IN.flag[a]==0)	//开始
			{
				TIM3_IN.flag[a]++;
//				TIM3->CNT=0;
				if(!a)
				{
					__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);
					HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);					
				}
				else
				{
					__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_RISING);
					HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2);					
				}

				TIME_TASK.OVERTIME[a+1]=1000;				
			}
			else if(TIM3_IN.flag[a]==4)	//结束,计算结果
			{
				TIM3_IN.flag[a]=0;
				
				TIM3_IN.zkb[a]=(TIM3_IN.TIME_TWO[a]-TIM3_IN.TIME_OEN[a])*100;
				if(TIM3_IN.zkb[a]) TIM3_IN.zkb[a]/=(TIM3_IN.TIME_THREE[a]-TIM3_IN.TIME_OEN[a]);
				
				if(!a)
				{
					if(TIM3_IN.zkb[a]<=10) data=0.0;
					else if(TIM3_IN.zkb[a]>=90) data=180.0;
					else
					{
						data=(TIM3_IN.zkb[a]-10)*2.25;	//180-(90-10)=2.25
					}
					
					if(DATA.a>data) DATA.ax=DATA.a-data;
					else DATA.ax=data-DATA.a;
					DATA.a=data;
					
					if(DATA.ax>DATA.Pax) led_state&=(~LD1);
					else 				 led_state|=LD1;			
					
					sprintf((char *)LCD_Line_buf[2],"   a:%-4.1f  ",DATA.a);
					sprintf((char *)LCD_Line_buf[6],"   ax:%-3d  ",DATA.ax);
					
					if(FLAG.display_mode==0) FLAG.display_Refresh|= LCD_Line2|LCD_Line6;
				}
				else
				{
					if(TIM3_IN.zkb[a]<=10) data=0.0;
					else if(TIM3_IN.zkb[a]>=90) data=90.0;
					else
					{
						data=(TIM3_IN.zkb[a]-10)*1.125;	//90-(90-10)=2.25
					}
					
					if(DATA.b>data) DATA.bx=DATA.b-data;
					else DATA.bx=data-DATA.b;
					DATA.b=data;

					if(DATA.bx>DATA.Pbx) led_state&=(~LD2);
					else 				 led_state|=LD2;

					//吊绳与吊臂之间的夹角
					if(DATA.a<(90+DATA.b))	DATA.ab=90-DATA.a+DATA.b;
					else					DATA.ab=DATA.a-90-DATA.b;
					
					if(DATA.ab<10) led_state&=(~LD5);
					else 		   led_state|=LD5;

					if(!DATA.Flag) //上电采集前5次
					{
						DATA.a_buf[DATA.num]=DATA.a;
						DATA.b_buf[DATA.num]=DATA.b;
						
						DATA.a_buf_Size[DATA.num]=DATA.a;
						DATA.b_buf_Size[DATA.num]=DATA.b;
						if(++DATA.num==5) {DATA.num=0;DATA.Flag=1;}
					}
					else
					{
						Shift_array_left(DATA.a_buf,5);
						Shift_array_left(DATA.b_buf,5);
						DATA.a_buf[4]=DATA.a;
						DATA.b_buf[4]=DATA.b;
						
						DATA.a_buf_Size[DATA.num]=DATA.a;
						DATA.b_buf_Size[DATA.num]=DATA.b;
						if(++DATA.num==5) {DATA.num=0;}						
					}
					
					sprintf((char *)LCD_Line_buf[3],"   b:%-4.1f  ",DATA.b);
					sprintf((char *)LCD_Line_buf[7],"   bx:%-3d  ",DATA.bx);
					
					if(FLAG.display_mode==0) FLAG.display_Refresh|= LCD_Line3|LCD_Line7;			
				}
				
				FLAG.measure_pwm&=(~(0x01<<a));	
			}
			else	//超时
			{				
				if(!TIME_TASK.OVERTIME[a+1])
				{
					if(!a) 
					{
						HAL_TIM_IC_Stop_IT(&htim3,TIM_CHANNEL_1);
						if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6))	{TIM3_IN.TIME_TWO[a]=1;TIM3_IN.TIME_THREE[a]=1;}	
						else	{TIM3_IN.TIME_TWO[0]=0;}						
					}
					else
					{
						HAL_TIM_IC_Stop_IT(&htim3,TIM_CHANNEL_2);
						if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7))	{TIM3_IN.TIME_TWO[a]=1;TIM3_IN.TIME_THREE[a]=1;}	
						else	{TIM3_IN.TIME_TWO[0]=0;}						
					}				
					TIM3_IN.TIME_OEN[a]=0;
					TIM3_IN.flag[a]=4;
				}
			}			
		}		
	}
}

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim==(&htim2))
	{
		if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_2)
		{
			if(TIM2_IN.flag[1]==1)
			{
				TIM2_IN.flag[1]++;
				TIM2_IN.TIME_OEN[1]=TIM2->CCR2;
			}
			else if(TIM2_IN.flag[1]==2)
			{
				TIM2_IN.flag[1]++;
				TIM2_IN.TIME_TWO[1]=TIM2->CCR2;				
				HAL_TIM_IC_Stop_IT(&htim2,TIM_CHANNEL_2);
			}
		}
	}
	if(htim==(&htim3))
	{
		if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)
		{
			if(TIM3_IN.flag[0]==1)
			{
				__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);
				TIM3_IN.flag[0]++;
				TIM3_IN.TIME_OEN[0]=TIM3->CCR1;				
			}
			else if(TIM3_IN.flag[0]==2)
			{
				__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);
				TIM3_IN.flag[0]++;
				TIM3_IN.TIME_TWO[0]=TIM3->CCR1;				
			}
			else if(TIM3_IN.flag[0]==3)
			{
				HAL_TIM_IC_Stop_IT(&htim3,TIM_CHANNEL_1);
				TIM3_IN.flag[0]++;
				TIM3_IN.TIME_THREE[0]=TIM3->CCR1;							
			}
		}	
		if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_2)
		{
			if(TIM3_IN.flag[1]==1)
			{
				__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_FALLING);
				TIM3_IN.flag[1]++;
				TIM3_IN.TIME_OEN[1]=TIM3->CCR2;				
			}
			else if(TIM3_IN.flag[1]==2)
			{
				__HAL_TIM_SET_CAPTUREPOLARITY(&htim3,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_RISING);
				TIM3_IN.flag[1]++;
				TIM3_IN.TIME_TWO[1]=TIM3->CCR2;				
			}
			else if(TIM3_IN.flag[1]==3)
			{
				HAL_TIM_IC_Stop_IT(&htim3,TIM_CHANNEL_2);
				TIM3_IN.flag[1]++;
				TIM3_IN.TIME_THREE[1]=TIM3->CCR2;							
			}
		}		
	}
}

程序下载

下载链接:
链接:https://pan.baidu.com/s/1LMECSy3GuABduu42YUJdSQ
提取码:qy2o

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值