蓝桥杯嵌入式CT117E硬件开发平台经验分享10 | 第八届蓝桥杯国赛题

频率控制器的功能设计与实现

硬件框图

在根据蓝桥杯题目设计工程代码时注意的为:先一步一步实现功能,每做一个功能最好设计一个副本,这样才能保证制作好的功能不丢失,哪怕新设计的功能无效也能迅速回退到上个功能版本。

例图

在本届国赛题的难点为:脉冲捕获、分频和倍频输出、双路ADC;其它的如LED,LCD,E2PROM都是相对简单的,在此不做赘述。

1、脉冲捕获,根据扩展板和原理图可以知道连接的为PA1和PA2接口。运用的为定时器2,CH2和CH3通道进行脉冲捕获。.h和.c代码如下:

#ifndef __BSP_GENERALCAP_H
#define __BSP_GENERALCAP_H

#include "stm32f10x.h"
#include "Def_config.h"
/************通用定时器TIM参数定义,只限TIM2、3、4************/

// 定时器输入捕获用户自定义变量结构体声明
typedef struct
{   
	u8   Capture_StartFlag;    // 捕获开始标志位
	u32  Capture_CcrValue_1;
	u32  Capture_CcrValue_2;  
	u32  Capture_CcrValue;     // 捕获寄存器的值
	u32  Capture_Period;       // 溢出次数 。计算后手动清零!
	u32  Capture_Frequency;    //频率
	JUDGE_ENUM   Capture_Success;  //成功标志
}TIM_ICUserValueTypeDef;
extern TIM_ICUserValueTypeDef TIM_ICUserValueStructure;
extern TIM_ICUserValueTypeDef TIM_ICUserValueStructure_CH3;

#define GENERAL_CAP_IRQ        TIM2_IRQn
#define GENERAL_CAP_TIM        TIM2
#define GENERAL_CAP_CLK        RCC_APB1Periph_TIM2
#define GENERAL_CAP_CHANNEL_02    TIM_Channel_2

#define GENERAL_CAP_GPIO_CLK      RCC_APB2Periph_GPIOA
#define GENERAL_CAP_PORT          GPIOA
#define GENERAL_CAP_PIN_02        GPIO_Pin_1

#define GENERAL_CAP_ITCCR_02            TIM_IT_CC2  
#define GENERAL_CAP_GetCapture_02       TIM_GetCapture2

// CH3  
#define GENERAL_CAP_CHANNE0L_03      TIM_Channel_3
#define GENERAL_CAP_PIN_03           GPIO_Pin_2

#define GENERAL_CAP_ITCCR_03            TIM_IT_CC3  
#define GENERAL_CAP_GetCapture_03       TIM_GetCapture3
/**************************函数声明********************************/
extern void GENERAL_CAP_Init(void);
extern void GENERAL_CAP_Interrupt(void);


/********************* TIM3 CAP******************************
#define GENERAL_CAP_IRQ        TIM3_IRQn
#define GENERAL_CAP_TIM        TIM3
#define GENERAL_CAP_CLK        RCC_APB1Periph_TIM3
#define GENERAL_CAP_CHANNEL    TIM_Channel_2

#define GENERAL_CAP_GPIO_CLK      RCC_APB2Periph_GPIOA
#define GENERAL_CAP_PORT          GPIOA
#define GENERAL_CAP_PIN           GPIO_Pin_7

#define GENERAL_CAP_ITCCR_02            TIM_IT_CC2  
#define GENERAL_CAP_GetCapture_02       TIM_GetCapture2
************************************************************/

#endif

#include "bsp_GeneralCap.h"
/************************************
原理都一样,无非是不同定时器而已,
使用注意: PA1: TIM2 - CH2    捕获通道
		   PA2: TIM2 - CH3 
		   
		   PA6: TIM3 - CH1
		   PA7: TIM3 - CH2
*************************************/
// 中断优先级配置
static void GENERAL_TIM_NVIC_CapConfig(void)
{
    NVIC_InitTypeDef NVIC_InitStructure; 
    // 设置中断组为0
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);		
		// 设置中断来源
    NVIC_InitStructure.NVIC_IRQChannel = GENERAL_CAP_IRQ;	  
		// 设置主优先级为 0
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	 
	  // 设置抢占优先级为3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_Priority_Structure.CAP_Priority;	
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

static void GENERAL_TIM_GPIO_CapConfig(void) 
{
	GPIO_InitTypeDef GPIO_InitStructure;

	// 输入捕获通道 GPIO 初始化
	RCC_APB2PeriphClockCmd(GENERAL_CAP_GPIO_CLK, ENABLE);
	GPIO_InitStructure.GPIO_Pin =  GENERAL_CAP_PIN_02 | GENERAL_CAP_PIN_03;	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GENERAL_CAP_PORT, &GPIO_InitStructure);	
}
/* ----------------   PWM信号 周期和占空比的计算--------------- */
// ARR :自动重装载寄存器的值
// CLK_cnt:计数器的时钟,等于 Fck_int / (psc+1) = 72M/(psc+1)
// PWM 信号的周期 T = ARR * (1/CLK_cnt) = ARR*(PSC+1) / 72M
// 占空比P=CCR/(ARR+1)

static void GENERAL_TIM_Mode_CapConfig(void)
{
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
  // 开启定时器时钟,即内部时钟CK_INT=72M
	RCC_APB1PeriphClockCmd(GENERAL_CAP_CLK,ENABLE);

/*--------------------时基结构体初始化-------------------------*/	   
	// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
	TIM_TimeBaseStructure.TIM_Period = 0xffff;	
	// 驱动CNT计数器的时钟 = Fck_int/(psc+1)
	TIM_TimeBaseStructure.TIM_Prescaler = 71;	
	// 时钟分频因子 ,配置死区时间时需要用到
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;		
	// 计数器计数模式,设置为向上计数
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;		
	// 初始化定时器
	TIM_TimeBaseInit(GENERAL_CAP_TIM, &TIM_TimeBaseStructure);

	/*--------------------输入捕获结构体初始化-------------------*/	
	
	// 配置输入捕获的通道,需要根据具体的GPIO来配置
	TIM_ICInitStructure.TIM_Channel = GENERAL_CAP_CHANNEL_02;
	// 输入捕获信号的极性配置
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
	// 输入通道和捕获通道的映射关系,有直连和非直连两种
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
	// 输入的需要被捕获的信号的分频系数
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
	// 输入的需要被捕获的信号的滤波系数
	TIM_ICInitStructure.TIM_ICFilter = 0;
	// 定时器输入捕获初始化
	TIM_ICInit(GENERAL_CAP_TIM, &TIM_ICInitStructure);
	
	//配置第三通道
	TIM_ICInitStructure.TIM_Channel = GENERAL_CAP_CHANNE0L_03;
	TIM_ICInit(GENERAL_CAP_TIM, &TIM_ICInitStructure);
	
  // 开启更新和捕获中断  
	TIM_ITConfig (GENERAL_CAP_TIM, TIM_IT_Update | GENERAL_CAP_ITCCR_02 | GENERAL_CAP_ITCCR_03, ENABLE );  //TIM_IT_Update 防止溢出中断允许
	  
	// 使能计数器
	TIM_Cmd(GENERAL_CAP_TIM, ENABLE);
}

void GENERAL_CAP_Init(void)
{
	GENERAL_TIM_GPIO_CapConfig();
	GENERAL_TIM_NVIC_CapConfig();
	GENERAL_TIM_Mode_CapConfig();		
}
//TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising); //设置上升沿捕获
// 定时器输入捕获用户自定义变量结构体定义
TIM_ICUserValueTypeDef TIM_ICUserValueStructure = {0,0,0,0,0,0,FALSE}; 
TIM_ICUserValueTypeDef TIM_ICUserValueStructure_CH3 = {0,0,0,0,0,0,FALSE};
void GENERAL_CAP_Interrupt(void)
{	
	if(TIM_GetFlagStatus(GENERAL_CAP_TIM,TIM_IT_Update) == SET){
		//清除标志位
		TIM_ClearITPendingBit(GENERAL_CAP_TIM,TIM_IT_Update);
		if(TIM_ICUserValueStructure.Capture_Success == FALSE)
		{
			TIM_ICUserValueStructure.Capture_Period ++;	//溢出!
			if(TIM_ICUserValueStructure.Capture_Period > 16)   //若大于1S,频率小于1HZ,
			{			
				TIM_ICUserValueStructure.Capture_CcrValue_1 = 0;
				TIM_ICUserValueStructure.Capture_CcrValue_2 = 0;
				TIM_ICUserValueStructure.Capture_CcrValue = 0;
				TIM_ICUserValueStructure.Capture_StartFlag = 0;				
				TIM_ICUserValueStructure.Capture_Frequency = 0; //频率为0 
				TIM_ICUserValueStructure.Capture_Period = 0;
				TIM_ICUserValueStructure.Capture_Success = TRUE;
			}
		}
		if(TIM_ICUserValueStructure_CH3.Capture_Success == FALSE)
		{
			TIM_ICUserValueStructure_CH3.Capture_Period ++;	//溢出!
			if(TIM_ICUserValueStructure_CH3.Capture_Period > 16)   //若大于1S,频率小于1HZ,
			{				
				TIM_ICUserValueStructure_CH3.Capture_CcrValue_1 = 0;
				TIM_ICUserValueStructure_CH3.Capture_CcrValue_2 = 0;
				TIM_ICUserValueStructure_CH3.Capture_CcrValue = 0;
				TIM_ICUserValueStructure_CH3.Capture_StartFlag = 0;				
				TIM_ICUserValueStructure_CH3.Capture_Frequency = 0; //频率为0 
				TIM_ICUserValueStructure_CH3.Capture_Period = 0;
				TIM_ICUserValueStructure_CH3.Capture_Success = TRUE;
			}
		}
	}
	
	if(TIM_GetFlagStatus(GENERAL_CAP_TIM,GENERAL_CAP_ITCCR_02) == SET)
	{
		TIM_ClearITPendingBit(GENERAL_CAP_TIM,GENERAL_CAP_ITCCR_02);
		if(TIM_ICUserValueStructure.Capture_Success == FALSE)
		{
			if(TIM_ICUserValueStructure.Capture_StartFlag == 0)
			{
				TIM_ICUserValueStructure.Capture_CcrValue_1 = GENERAL_CAP_GetCapture_02(GENERAL_CAP_TIM);
				TIM_ICUserValueStructure.Capture_StartFlag = 1;
			}
			else
			{
				TIM_ICUserValueStructure.Capture_CcrValue_2 = GENERAL_CAP_GetCapture_02(GENERAL_CAP_TIM);			
				TIM_ICUserValueStructure.Capture_StartFlag = 0;						
				TIM_ICUserValueStructure.Capture_Success = TRUE;		
			}
		}
	}	
	if(TIM_GetFlagStatus(GENERAL_CAP_TIM,GENERAL_CAP_ITCCR_03) == SET)
	{
		TIM_ClearITPendingBit(GENERAL_CAP_TIM,GENERAL_CAP_ITCCR_03);
		if(TIM_ICUserValueStructure_CH3.Capture_Success == FALSE)
		{
			if(TIM_ICUserValueStructure_CH3.Capture_StartFlag == 0)
			{
				TIM_ICUserValueStructure_CH3.Capture_CcrValue_1 = GENERAL_CAP_GetCapture_03(GENERAL_CAP_TIM);
				TIM_ICUserValueStructure_CH3.Capture_StartFlag = 1;
			}
			else
			{
				TIM_ICUserValueStructure_CH3.Capture_CcrValue_2 = GENERAL_CAP_GetCapture_03(GENERAL_CAP_TIM);				
				TIM_ICUserValueStructure_CH3.Capture_StartFlag = 0;		
				TIM_ICUserValueStructure_CH3.Capture_Success = TRUE;
			}
		}
	}
}
/*********************************************END OF FILE**********************/

调用方法思路:捕获函数其实仅仅是通过定时器将脉冲进行计数,但是具体的计算放到了main函数里,这样不占用太多中断时间,采集效果会好点。(中断里最好节省时间,能不用乘除法就不用,因为需要耗费时钟周期较久。)
if(TIM_ICUserValueStructure.Capture_Success == TRUE)
	{
		TIM_Cmd(GENERAL_CAP_TIM, DISABLE);
		if(TIM_ICUserValueStructure.Capture_Period == 0)
		{
			TIM_ICUserValueStructure.Capture_CcrValue = (TIM_ICUserValueStructure.Capture_CcrValue_2 - TIM_ICUserValueStructure.Capture_CcrValue_1);
		}
		else
		{
			TIM_ICUserValueStructure.Capture_CcrValue = (65536 * TIM_ICUserValueStructure.Capture_Period - TIM_ICUserValueStructure.Capture_CcrValue_1 + TIM_ICUserValueStructure.Capture_CcrValue_2);					
		}
		if(TIM_ICUserValueStructure.Capture_CcrValue != 0)
			TIM_ICUserValueStructure.Capture_Frequency = (u32)(1000000.0 / (TIM_ICUserValueStructure.Capture_CcrValue) + 0.5);
		else
			TIM_ICUserValueStructure.Capture_Frequency = 0; 
		LCDDISVALUE_DEF_Structure.Pulse_01 = TIM_ICUserValueStructure.Capture_Frequency; 
		if(TIM_ICUserValueStructure.Capture_Frequency != Capture01_Frequency_Last)
		{
			Capture01_Frequency_Last = TIM_ICUserValueStructure.Capture_Frequency;
			PWMTIM_Structure.PWMx_Ch1_Freq = GENERAL_PWM_Period_FrequencySet((u16)(TIM_ICUserValueStructure.Capture_Frequency*1.0/LCDDISVALUE_SET_Structure.Division_PA6_PA1));
			PWMTIM_Structure.PWMx_Ch1_DutyCycle = 0.5;
			PWMTIM_Structure.PWMx_Ch1_Freq_LowVolt = (u16)(PWMTIM_Structure.PWMx_Ch1_Freq * (1 - PWMTIM_Structure.PWMx_Ch1_DutyCycle)); 
			PWMTIM_Structure.PWMx_Ch1_Freq_highVolt = (u16)(PWMTIM_Structure.PWMx_Ch1_Freq * PWMTIM_Structure.PWMx_Ch1_DutyCycle);
		}
		TIM_ICUserValueStructure.Capture_CcrValue_1 = 0;
		TIM_ICUserValueStructure.Capture_CcrValue_2 = 0;
		TIM_ICUserValueStructure.Capture_CcrValue = 0;
		TIM_ICUserValueStructure.Capture_StartFlag = 0;				
		TIM_ICUserValueStructure.Capture_Frequency = 0; //频率为0 
		TIM_ICUserValueStructure.Capture_Period = 0;
		TIM_ICUserValueStructure.Capture_Success = FALSE;  
		TIM_Cmd(GENERAL_CAP_TIM, ENABLE);
	}
	if(TIM_ICUserValueStructure_CH3.Capture_Success == TRUE)
	{
		TIM_Cmd(GENERAL_CAP_TIM, DISABLE);
		if(TIM_ICUserValueStructure_CH3.Capture_Period == 0)
		{
			TIM_ICUserValueStructure_CH3.Capture_CcrValue = (TIM_ICUserValueStructure_CH3.Capture_CcrValue_2 - TIM_ICUserValueStructure_CH3.Capture_CcrValue_1);
		}
		else
		{
			TIM_ICUserValueStructure_CH3.Capture_CcrValue = (65536 * TIM_ICUserValueStructure_CH3.Capture_Period - TIM_ICUserValueStructure_CH3.Capture_CcrValue_1 + TIM_ICUserValueStructure_CH3.Capture_CcrValue_2);					
		}
		if(TIM_ICUserValueStructure_CH3.Capture_CcrValue != 0)
			TIM_ICUserValueStructure_CH3.Capture_Frequency = (u32)(1000000.0 / (TIM_ICUserValueStructure_CH3.Capture_CcrValue) + 0.5);  // (1000000.0 / (TIM_ICUserValueStructure_CH3.Capture_CcrValue) + 0.5) 得结果为HZ,需要转为KHz
		else
			TIM_ICUserValueStructure_CH3.Capture_Frequency = 0; 
		LCDDISVALUE_DEF_Structure.Pulse_02 = TIM_ICUserValueStructure_CH3.Capture_Frequency;
		if(TIM_ICUserValueStructure_CH3.Capture_Frequency != Capture02_Frequency_Last)
		{
			Capture02_Frequency_Last = TIM_ICUserValueStructure_CH3.Capture_Frequency;
			PWMTIM_Structure.PWMx_Ch2_Freq = GENERAL_PWM_Period_FrequencySet((u16)(TIM_ICUserValueStructure_CH3.Capture_Frequency * LCDDISVALUE_SET_Structure.Multiply_PA7_PA2));
			PWMTIM_Structure.PWMx_Ch2_DutyCycle = 0.5;			
			PWMTIM_Structure.PWMx_Ch2_Freq_LowVolt = (u16)(PWMTIM_Structure.PWMx_Ch2_Freq * (1 - PWMTIM_Structure.PWMx_Ch2_DutyCycle)); 
			PWMTIM_Structure.PWMx_Ch2_Freq_highVolt = (u16)(PWMTIM_Structure.PWMx_Ch2_Freq * PWMTIM_Structure.PWMx_Ch2_DutyCycle); 
		}
		TIM_ICUserValueStructure_CH3.Capture_CcrValue_1 = 0;
		TIM_ICUserValueStructure_CH3.Capture_CcrValue_2 = 0;
		TIM_ICUserValueStructure_CH3.Capture_CcrValue = 0;
		TIM_ICUserValueStructure_CH3.Capture_StartFlag = 0;				
		TIM_ICUserValueStructure_CH3.Capture_Frequency = 0; //频率为0 
		TIM_ICUserValueStructure_CH3.Capture_Period = 0;
		TIM_ICUserValueStructure_CH3.Capture_Success = FALSE;
		TIM_Cmd(GENERAL_CAP_TIM, ENABLE);
	}

分频和倍频输出,.c和.h都放出。调用方法在捕获的调用方法里已经给出,就是判断当频率和上次存的频率不同时,通过通过PWM的Toggle模式输出的值。

#ifndef __BSP_GENERALPWM_H
#define __BSP_GENERALPWM_H


#include "stm32f10x.h"
#include "Def_config.h"

typedef struct{		
	__IO u16 PWMx_Ch1_Freq; 
	float PWMx_Ch1_DutyCycle;
	__IO u16 PWMx_Ch1_Freq_LowVolt;
	__IO u16 PWMx_Ch1_Freq_highVolt;	

	__IO u16 PWMx_Ch2_Freq;
	float PWMx_Ch2_DutyCycle;
	__IO u16 PWMx_Ch2_Freq_LowVolt;
	__IO u16 PWMx_Ch2_Freq_highVolt;

	JUDGE_ENUM TIM3_OutputLowVolt;
}PWMTIM_TypeDef;
extern PWMTIM_TypeDef PWMTIM_Structure;
/*******************  PWM模式调节TIM3 *************************/
#define            GENERAL_PWM_TIM               TIM3 

/*******************  PWM模式调节 TIM_OCMode_Toggle*************************/
#define  TIM_OCMode_SET      TIM_OCMode_Toggle  
//最低输出20HZ,最高1M  TIM_OCMode_Toggle下TIM_OCInitStructure.TIM_Pulse的值,决定频率
#define            GENERAL_PWM_Period_FrequencySet(X)       (u16)(1000000.0/X + 0.5)   //X:Frequency 

#define            GENERAL_PWM_CCRx           PWMTIM_Structure.PWMx_Ch1_Freq
#define            GENERAL_PWM_CCRx_CH2          PWMTIM_Structure.PWMx_Ch2_Freq

/**************************函数声明********************************/

extern void GENERAL_PWM_Init(void);
void GENERAL_PWM_FrequecyAndDutyCycle(STATE_ENUM TIM3_OutputState);
extern void GENERAL_PWM_Interrupt(void);

#endif	/* __BSP_GENERALPWME_H */

#include "bsp_GeneralPwm.h" 
/*******************************************************************************  
* 文件名称:通用定时器PWM驱动
* 作者:    PANDAS
* 单位:    广西师范大学电子工程学院电子与通信工程研究生
* 联系方式:lpf0503@hotmail.com
* 实验目的:1.学习  PWM模式TIM_OCMode_PWM1 ;TIM_OCMode_PWM2  模式
*           2.学习  PWM模式TIM_OCMode_Toggle 模式
* 程序说明:1.
*           2.
* 日期版本:2020-10-17  V1.0
*******************************************************************************/
static void GENERAL_PWM_GPIO_Config(void) 
{
	GPIO_InitTypeDef GPIO_InitStructure;

	// 输出比较通道1 GPIO 初始化   // 输出比较通道2 GPIO 初始化
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //默认复用功能不用开启复用时钟
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
	GPIO_Init(GPIOA, &GPIO_InitStructure);	 
} 
static void GENERAL_NORMAL_GPIO_Config(void) 
{
	GPIO_InitTypeDef GPIO_InitStructure;

	// 输出比较通道1 GPIO 初始化   // 输出比较通道2 GPIO 初始化
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	 //不产生PWM时输出高低电平
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   
	GPIO_Init(GPIOA, &GPIO_InitStructure);	 
} 
// 中断优先级配置
static void GENERAL_PWM_NVIC_PwmConfig(void)
{
    NVIC_InitTypeDef NVIC_InitStructure; 
    // 设置中断组为0
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);		
		// 设置中断来源
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn ;	
		// 设置主优先级为 0
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_Priority_Structure.PWM_Priority;	
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;      
    NVIC_Init(&NVIC_InitStructure);       
}
static void GENERAL_PWM_Mode_Config(void)     
{
    TIM_OCInitTypeDef  TIM_OCInitStructure;  
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;   
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);   

/*--------------------时基结构体初始化-------------------------*/
	TIM_TimeBaseStructure.TIM_Period = 0xffff;	
	TIM_TimeBaseStructure.TIM_Prescaler= 71;		
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;	
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //!!!keil5少了无法启动
	TIM_TimeBaseInit(GENERAL_PWM_TIM, &TIM_TimeBaseStructure);

	/*--------------------输出比较结构体初始化-------------------*/	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_SET;              
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //当定时器计数值小于CCR1_Val时的电平
	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
	
	// 输出比较通道 
	TIM_OCInitStructure.TIM_Pulse = GENERAL_PWM_CCRx;   	//CCRx 有序号区分!!
	TIM_OC1Init(GENERAL_PWM_TIM, &TIM_OCInitStructure);   //OCx  有序号区分!!!	
	TIM_OC1PreloadConfig(GENERAL_PWM_TIM, TIM_OCPreload_Disable);      //TIM_OCMode_PWM1模式下!!!!使能或者失能TIMx在CCR1上的预装载寄存器
      
	// 输出比较通道    
	TIM_OCInitStructure.TIM_Pulse = GENERAL_PWM_CCRx_CH2;   	//CCRx 有序号区分!!
	TIM_OC2Init(GENERAL_PWM_TIM, &TIM_OCInitStructure);   //OCx  有序号区分!!!	
	TIM_OC2PreloadConfig(GENERAL_PWM_TIM, TIM_OCPreload_Disable);      //TIM_OCMode_PWM1模式下!!!!使能或者失能TIMx在CCR1上的预装载寄存器

	//使能TIM_OCMode_Toggle模式的 GENERAL_PWM_ITCCX 中断
	TIM_ITConfig(GENERAL_PWM_TIM,TIM_IT_CC1 | TIM_IT_CC2,ENABLE);   

	// 使能计数器
	TIM_Cmd(GENERAL_PWM_TIM, ENABLE);	
}
PWMTIM_TypeDef PWMTIM_Structure;
void GENERAL_PWM_Init(void)
{
	PWMTIM_Structure.PWMx_Ch1_Freq = GENERAL_PWM_Period_FrequencySet(1000);
	PWMTIM_Structure.PWMx_Ch1_DutyCycle = 0.5;
	PWMTIM_Structure.PWMx_Ch1_Freq_LowVolt = (u16)(PWMTIM_Structure.PWMx_Ch1_Freq * (1 - PWMTIM_Structure.PWMx_Ch1_DutyCycle)); 
	PWMTIM_Structure.PWMx_Ch1_Freq_highVolt = (u16)(PWMTIM_Structure.PWMx_Ch1_Freq * PWMTIM_Structure.PWMx_Ch1_DutyCycle);

	PWMTIM_Structure.PWMx_Ch2_Freq = GENERAL_PWM_Period_FrequencySet(2000);
	PWMTIM_Structure.PWMx_Ch2_DutyCycle = 0.5;			
	PWMTIM_Structure.PWMx_Ch2_Freq_LowVolt = (u16)(PWMTIM_Structure.PWMx_Ch2_Freq * (1 - PWMTIM_Structure.PWMx_Ch2_DutyCycle)); 
	PWMTIM_Structure.PWMx_Ch2_Freq_highVolt = (u16)(PWMTIM_Structure.PWMx_Ch2_Freq * PWMTIM_Structure.PWMx_Ch2_DutyCycle); 
	
	GENERAL_PWM_GPIO_Config();
	GENERAL_PWM_NVIC_PwmConfig();
	GENERAL_PWM_Mode_Config();		
}
void GENERAL_PWM_FrequecyAndDutyCycle(STATE_ENUM TIM3_OutputState)
{
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	TIM_ITConfig(GENERAL_PWM_TIM,TIM_IT_CC1 | TIM_IT_CC2,DISABLE);    //TIM_OCMode_PWM1模式下采用中断
	TIM_Cmd(GENERAL_PWM_TIM, DISABLE);
	if(TIM3_OutputState == ON)
	{	
		GENERAL_PWM_GPIO_Config(); //重新配置GPIO
		TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_SET;              
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
		TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //当定时器计数值小于CCR1_Val时的电平
		TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
		
		// 输出比较通道 
		TIM_OCInitStructure.TIM_Pulse = PWMTIM_Structure.PWMx_Ch1_Freq;   	//CCRx 有序号区分!!
		TIM_OC1Init(GENERAL_PWM_TIM, &TIM_OCInitStructure);   //OCx  有序号区分!!!	
		TIM_OC1PreloadConfig(GENERAL_PWM_TIM, TIM_OCPreload_Disable);      //TIM_OCMode_PWM1模式下!!!!使能或者失能TIMx在CCR1上的预装载寄存器
	      
		// 输出比较通道    
		TIM_OCInitStructure.TIM_Pulse = PWMTIM_Structure.PWMx_Ch2_Freq;   	//CCRx 有序号区分!!
		TIM_OC2Init(GENERAL_PWM_TIM, &TIM_OCInitStructure);   //OCx  有序号区分!!!	
		TIM_OC2PreloadConfig(GENERAL_PWM_TIM, TIM_OCPreload_Disable);      //TIM_OCMode_PWM1模式下!!!!使能或者失能TIMx在CCR1上的预装载寄存器
		
		TIM_ITConfig(GENERAL_PWM_TIM,TIM_IT_CC1 | TIM_IT_CC2,ENABLE);    
		TIM_Cmd(GENERAL_PWM_TIM, ENABLE);
	}
	else
	{
		GENERAL_NORMAL_GPIO_Config();
		if(PWMTIM_Structure.TIM3_OutputLowVolt == TRUE)
			GPIO_ResetBits(GPIOA,GPIO_Pin_6 | GPIO_Pin_7); 	
		else
			GPIO_SetBits(GPIOA,GPIO_Pin_6 | GPIO_Pin_7); 	
	}	
}
u8 PWM_Interrupt_Count = 0;
u8 PWM_Interrupt_Count_CH2 = 0;
void GENERAL_PWM_Interrupt(void)
{
	u16 capture = 0;
	if(TIM_GetFlagStatus(GENERAL_PWM_TIM,TIM_IT_CC1) == SET)
	{
		TIM_ClearITPendingBit(GENERAL_PWM_TIM,TIM_IT_CC1);
		capture = TIM_GetCapture1(GENERAL_PWM_TIM);   //!!! 有序号区分
		if(PWM_Interrupt_Count == 0)
		{	 			
			TIM_SetCompare1(GENERAL_PWM_TIM,capture + PWMTIM_Structure.PWMx_Ch1_Freq_LowVolt);  // TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; 第一次中断后设置的为此TIM_OCPolarity_Low决定的有效电平
			PWM_Interrupt_Count = 1;
		}
		else
		{			
			TIM_SetCompare1(GENERAL_PWM_TIM,capture + PWMTIM_Structure.PWMx_Ch1_Freq_highVolt);
			PWM_Interrupt_Count = 0;
		}
	}
	if(TIM_GetFlagStatus(GENERAL_PWM_TIM,TIM_IT_CC2) == SET)
	{
		TIM_ClearITPendingBit(GENERAL_PWM_TIM,TIM_IT_CC2);
		capture = TIM_GetCapture2(GENERAL_PWM_TIM);   //!!! 有序号区分
		if(PWM_Interrupt_Count_CH2 == 0)
		{	 			
			TIM_SetCompare2(GENERAL_PWM_TIM,capture + PWMTIM_Structure.PWMx_Ch2_Freq_LowVolt);  // TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; 第一次中断后设置的为此TIM_OCPolarity_Low决定的有效电平
			PWM_Interrupt_Count_CH2 = 1;
		}
		else
		{			
			TIM_SetCompare2(GENERAL_PWM_TIM,capture + PWMTIM_Structure.PWMx_Ch2_Freq_highVolt);
			PWM_Interrupt_Count_CH2 = 0;
		}
	}
}
/*********************************************END OF FILE**********************/

双通道ADC扫描(中断模式)

采用此模式也可以,当然也可以采用DMA模式。更加方便和直接。由于本人也是从入门开始学习STM32来参加比赛的,在准备的这些时间,一步一步不断更新自己的思维逻辑和功能实现方法,后续会有DMA方式的代码。
#ifndef __ADC_H
#define	__ADC_H


#include "stm32f10x.h"
#include "Def_config.h"

// ADC 编号选择
// 可以是 ADC1/2,如果使用ADC3,中断相关的要改成ADC3的
#define    ADCx                          ADC1
#define    ADC_CLK                       RCC_APB2Periph_ADC1

// ADC GPIO宏定义
// 注意:用作ADC采集的IO必须没有复用,否则采集电压会有影响
#define    ADC_GPIO_CLK                  RCC_APB2Periph_GPIOA  
#define    ADC_PORT                      GPIOA
#define    ADC_PIN                       (GPIO_Pin_4 | GPIO_Pin_5)
// ADC 通道宏定义
//#define    ADC_CHANNEL                   ADC_Channel_8

// ADC 中断相关宏定义
#define    ADC_IRQ                       ADC1_2_IRQn
#define    ADC_IRQHandler                ADC1_2_IRQHandler

//#define    ADC_IRQ                       ADC3_IRQn
//#define    ADC_IRQHandler                ADC3_IRQHandler
typedef struct{				
	uint16_t ADC_ConvertedValue;
	float ADC_Voltage;  
	JUDGE_ENUM IS_ADCConvertComplete;
}ADCREAD_TypeDef;
extern ADCREAD_TypeDef ADCREAD_Structure;


extern void ADCx_Init(void);
extern void ADC_Read_Interrupt(void);

#endif /* __ADC_H */


#include "bsp_adc.h"
/*******************************************************************************  
* 文件名称:ADC采集驱动
* 作者:    PANDAS
* 单位:    广西师范大学电子工程学院电子与通信工程研究生
* 联系方式:lpf0503@hotmail.com
* 实验目的:1.
*           2.
* 程序说明:1.开发板R37电位器: PB0-ADC1 channel 8   ADC1 12位分辨率 0xfff:2^12  = 4096
*           2.开发板RP5电位器: PA4-ADC1 channel 4 
			3.开发板RP6电位器: PA5-ADC1 channel 5 
* 日期版本:2020-10-17  V1.0
*******************************************************************************/
/**
  * @brief  配置ADC中断优先级
  * @param  无
  * @retval 无
  * @attention   NVIC_Priority_Structure.ADC1CH8_Priority;不要忘了配置
  *              NVIC_Priority_Structure包含于	#include "Def_config.h"
  */
static void ADC_NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	// 优先级分组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

	// 配置中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQ;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = NVIC_Priority_Structure.ADC1_RPx_Priority;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}
/**
  * @brief  ADC GPIO 初始化
  * @param  无
  * @retval 无
  */
static void ADCx_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	// 打开 ADC IO端口时钟
	RCC_APB2PeriphClockCmd( ADC_GPIO_CLK, ENABLE );
	
	// 配置 ADC IO 引脚模式
	// 必须为模拟输入
	GPIO_InitStructure.GPIO_Pin = ADC_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	
	// 初始化 ADC IO
	GPIO_Init(ADC_PORT, &GPIO_InitStructure);				
}
/**
  * @brief  配置ADC工作模式
  * @param  无
  * @retval 无
  */
static void ADCx_Mode_Config(void)
{
	ADC_InitTypeDef ADC_InitStructure;	

	// 打开ADC时钟
	RCC_APB2PeriphClockCmd( ADC_CLK, ENABLE );
	
	// ADC 模式配置
	// 只使用一个ADC,属于独立模式
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	
	// 禁止扫描模式,多通道才要,单通道不需要
	ADC_InitStructure.ADC_ScanConvMode = DISABLE ; 

	// 连续转换模式
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; 

	// 不用外部触发转换,软件开启即可
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

	// 转换结果右对齐
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	
	// 转换通道x个
	ADC_InitStructure.ADC_NbrOfChannel = 1;	
		
	// 初始化ADC
	ADC_Init(ADCx, &ADC_InitStructure);
	
	// 配置ADC时钟为PCLK2的8分频,72/8 即9MHz
	RCC_ADCCLKConfig(RCC_PCLK2_Div8); 
	
	// 配置 ADC 通道转换顺序和采样时间
	ADC_RegularChannelConfig(ADCx, ADC_Channel_4, 1, ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADCx, ADC_Channel_5, 1, ADC_SampleTime_55Cycles5);
//	ADC_AutoInjectedConvCmd(ADCx,ENABLE);
	
	// ADC 转换结束产生中断,在中断服务程序中读取转换值
	ADC_ITConfig(ADCx, ADC_IT_EOC, ENABLE);
	
	// 开启ADC ,并开始转换
	ADC_Cmd(ADCx, ENABLE);
	
	// 初始化ADC 校准寄存器  
	ADC_ResetCalibration(ADCx);
	// 等待校准寄存器初始化完成
	while(ADC_GetResetCalibrationStatus(ADCx));
	
	// ADC开始校准
	ADC_StartCalibration(ADCx);
	// 等待校准完成
	while(ADC_GetCalibrationStatus(ADCx));
	
	// 由于没有采用外部触发,所以使用软件触发ADC转换 
	ADC_SoftwareStartConvCmd(ADCx, ENABLE);
	ADC_RegularChannelConfig(ADCx, ADC_Channel_4, 1, ADC_SampleTime_55Cycles5);
}
/**
  * @brief  ADC初始化
  * @param  无
  * @retval 无
  * @attention   别忘了main.c调用初始化
  */
void ADCx_Init(void)
{
	ADCx_GPIO_Config();
	ADCx_Mode_Config();
	ADC_NVIC_Config();
}
/**
  * @说明     ADC中断处理
  * @参数     none
  * @返回值   None
  * @包含出处  #include "bsp_GeneralPwm.h"
  * @注意     需要将此放入对应定时器的中断函数中
  *          如:在stm32f10x_it.c中:
  *			extern void ADC_Read_Interrupt(void);
  *			void TIM4_IRQHandler(void)  //根据自定PWM定时器的中断来做
  *			{
  *				ADC_Read_Interrupt();
  *			}
  */
ADCREAD_TypeDef ADCREAD_Structure;
void ADC_Read_Interrupt(void)
{
	if (ADC_GetITStatus(ADCx,ADC_IT_EOC) == SET) 
	{
		ADC_ClearITPendingBit(ADCx,ADC_IT_EOC);
		// 读取ADC的转换值
		ADCREAD_Structure.ADC_ConvertedValue = ADC_GetConversionValue(ADCx);
//		ADCREAD_Structure.ADC_Voltage = (float)(ADCREAD_Structure.ADC_ConvertedValue * 3.30 / 0xfff); //此类计算太耗时,不得放入中断函数!!!
		ADCREAD_Structure.IS_ADCConvertComplete = TRUE;
	}		
}
/*********************************************END OF FILE**********************/

END:当开始写国赛系列的博客时,已经结束了本年度的蓝桥杯国赛比赛,这些程序都是训练过程中写的代码,难免有所不足,望见谅。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值