stm32f103笔记


前言

103的外设使用,标准库


一、ADC

1、规则通道常用,注入通道不常用。
2、12位转换精度,注意采样时间,采样时间越短精度越低,例程是55
3、记得注意校准,标准库例程有校准,hal库没有。
4、hal记得要自己加上一句校准电压的代码

这里引脚有错

void adc_init(void){
	ADC_InitTypeDef ADC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6); 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
	
	 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	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;//采样数据右对齐
  ADC_InitStructure.ADC_NbrOfChannel = 1;//采样通道数量
  ADC_Init(ADC1, &ADC_InitStructure);

  /* ADC1 regular channel14 configuration */ 
  //ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_55Cycles5);//设置采样时间
  
  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);
//以下校准
  /* Enable ADC1 reset calibration register */   
  ADC_ResetCalibration(ADC1);
  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1));

  /* Start ADC1 calibration */
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));
     
  /* Start ADC1 Software Conversion */ 
  //ADC_SoftwareStartConvCmd(ADC1, ENABLE);//开始采样
}

采样电压处理

u16 get_adc(u8 channel){//得到未处理的值
	ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_55Cycles5);
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
	return ADC_GetConversionValue(ADC1);
	
}

float get_V(u8 channel){//均值滤波
	float temp;
	for(u8 i=0;i<10;i++){
	temp+=get_adc(channel)*3.3/4096;//注意这里先称后除,关系到类型转换,不这样可能会有bug
	}
	return temp/10;
}

二、按键处理

思路
1、阻塞死等,建议不用
2、引脚外部中断
3、状态机(推荐)

使用基本定时器tim6,每10秒一次更新中断,在中断里判断按键。

头文件


#define KEY0  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)//读取按键0
#define KEY1  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)//读取按键1
#define KEY2  GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)//读取按键2 
#define WK_UP   GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键3(WK_UP) 

 #define key_0 1
#define key_1 (1<<1)
#define key_2 (1<<2)
#define key_up (1<<3)

#define KEY0_PRES 	1	//KEY0按下
#define KEY1_PRES	2	//KEY1按下
#define KEY2_PRES	3	//KEY2按下
#define WKUP_PRES   4	//KEY_UP按下(即WK_UP/KEY_UP)

.c

void KEY_Init(void) //IO初始化
{ 
 	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);//使能PORTA,PORTE时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_3|GPIO_Pin_4;//KEY0-KEY1
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
 	GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化GPIOE3,4

	TIM_TimeBaseStructure.TIM_Period = 10000-1;
  TIM_TimeBaseStructure.TIM_Prescaler = 71;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	 TIM_Cmd(TIM6, ENABLE);

  TIM_ITConfig(TIM6,TIM_IT_Update, ENABLE);
}

按键扫描

//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//0,没有任何按键按下
//1,KEY0按下
//2,KEY1按下
//3,KEY2按下 
//4,KEY3按下 WK_UP
//注意此函数有响应优先级,KEY0>KEY1>KEY2>KEY3!!
u8 key_scan(void){
	u8 key_date=0;//每一位代表一个按键的状态,未按为0,按下置1
	if(!KEY0)key_date|=key_0;
	if(!KEY1)key_date|=key_1;
	//if(WK_UP)key_date|=key_up;
	return key_date;
}

key_flag是按键的状态函数,0表示在扫描中,1表示在处理,2表示处理完了可以清标志位了
key_temp是按键按下的状态,表示一组按键,如果确定按下了,那就根据它来选择执行的操作。


u8 key_flag=0;
u8 key_temp=0;
void TIM6_IRQHandler(void)
{ 
	u8 key_now;//临时保存扫描的按键状态
	static u8 key_time=0;//按下时间计数
  if(TIM_GetITStatus(TIM6, TIM_IT_Update) == SET) 
  {
    TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
		key_now=key_scan();
									if(key_flag==0){
											if(key_temp==0){//表示10ms前没有按键按下
												key_temp=key_now;
											}else{//表示10ms前有按键按下
												switch(key_temp){//根据按键钻状态进行消抖
													case key_0:
														if(++key_time>5){//50m消抖,其实10ms就够了,不过这里要判断是否两个按键一起按下。
																if(key_now&key_0){//如果按键现在还是按下的证明不是抖动
																	if(key_now&key_1){//多按判断,如果按键1也是按下就把它的标志位置1
																		key_temp|=key_1;
																	}
																	key_flag=1;//转到执行状态
																}else{
																key_temp=0;
																}
														}else{//消抖等待时间
															if(key_now==0)key_temp=0;//如果这段时间按键为0,表示是抖动,清标志位开始下一次
														}
														break;
													case key_1:
														if(++key_time>5){
																if(key_now&key_1){
																	if(key_now&key_0){
																		key_temp|=key_0;
																	}
																	key_flag=1;
																}else{
																key_temp=0;
																}
														}else{
															if(key_now==0)key_temp=0;
														}
														break;
													case key_1|key_0:
														key_flag=1;
														break;
														case key_2:
														if(key_temp==key_now){
															key_flag=1;
														}else{
														key_temp=0;
														}
														break;
														default:
															printf("按键错误\r\n");
															key_temp=0;
														break;
												}
											}
									}else if(key_flag==2){//按键功能执行完毕,清标志位
										if(key_now==0){//如果按键全都松开的,就清标志位,开始下一次
											key_flag=0;
											key_temp=0;
											key_time=0;
										}
									}
	}
}

按键处理

if(key_flag==1){
			
		switch(key_temp){//根据按键状态变量处理
		case key_0:
			
			
			break;
		case key_1:
			
			break;
		
	}
	key_flag=2;
	
		}

二、输入捕获

输入捕获pwm有硬件自带的,硬件的看例程即可,这里是捕获跳变沿的方法
如果同一个定时器两个通道都在捕获,可以分时复用解决冲突。

void ic_init(void){
	
	TIM_ICInitTypeDef  TIM_ICInitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	
	 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_TimeBaseStructure.TIM_Period = 0XFFFF;
  TIM_TimeBaseStructure.TIM_Prescaler = 71;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);

	NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
  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 = 0x0;

  TIM_ICInit(TIM5, &TIM_ICInitStructure);
 
  TIM_Cmd(TIM5, ENABLE);

  TIM_ITConfig(TIM5, TIM_IT_CC1|TIM_IT_Update, ENABLE);

}

在中断里判断,建议把高低电平时间,频率什么的都弄个结构体
因为这种捕获是使用在边沿跳变时的定时器的值,而如果像原子那样直接在第一次捕获时就清零计时器,然后以它为时间基点,会造成少几us的结果。
所以建议第一次清零,第二次捕获的ccr值作为时间基点计算。但这里的处理
是第一种,对时间要求不严格可以用,有准确度要求就用第二种方法。

u8 ic_flag=0;//捕获标志位,
u8 ic_overflow=0;//定时器捕获期间溢出标志位
u32 ic_h=0;//高电平时间

void TIM5_IRQHandler(void)
{ 
	if(TIM_GetITStatus(TIM5, TIM_IT_Update) == SET) 
  {
    TIM_ClearITPendingBit(TIM5, TIM_IT_Update);
			if(ic_flag==1){//这里应该是个范围,表示捕获开始到结束之间
			if(ic_overflow<200){
				ic_overflow++;
			}else{//大于这个时间就是超出处理能力,直接结束
				ic_flag=2;
			}
		}
	}
	
	
  if(TIM_GetITStatus(TIM5, TIM_IT_CC1) == SET) 
  {
    TIM_ClearITPendingBit(TIM5, TIM_IT_CC1);
		switch(ic_flag){
			case 0://捕获开始,清零cnt,初始标志位
				TIM5->CNT=0;
				ic_overflow=0;//注意改捕获边沿的函数hal和标准库不一样
			TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Falling);
				ic_flag++;
				break;
			case 1:
				ic_h=TIM5->CCR1;
				TIM_OC1PolarityConfig(TIM5, TIM_ICPolarity_Rising);
				ic_h+=ic_overflow*0xffff;
				if(ic_h>30000){//因为这里功能是检测按键按下时间,所以有个消抖
				TIM_ITConfig(TIM5, TIM_IT_CC1|TIM_IT_Update, DISABLE);
				ic_flag++;
				}else{
				ic_flag=0;
				ic_overflow=0;
				}
			break;
		}
  }
}

三、hal的输入捕获

这是hal库的写法用的上面说的带时间基点的方法,更准确,但思路是一样的。ic_flag=4时一次捕获完成。

void TIM2_IRQHandler(void)
{
  /* USER CODE BEGIN TIM2_IRQn 0 */
	if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_CC1) != RESET)
  {
        __HAL_TIM_CLEAR_IT(&htim2, TIM_IT_CC1);
		//printf("%u\r\n",TIM2->CCR1);
		switch(ic_flag){
			case 0://初始
				TIM2->CNT=0;
				//__HAL_TIM_SET_ICPRESCALER(&htim2, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);//注意这两有点像,不要搞错了,是capture开头不是ic开头
				ic_flag++;
				break;
			case 1://ic_h作为时间基础
				//ic_l=TIM2->CCR1;
			ic_h=HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);
				ic_flag++;
				break;
			case 2:
			//	ic_h=(TIM2->CCR1-ic_l);
			ic_l=HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1)-ic_h;
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_ICPOLARITY_FALLING);
				ic_flag++;
				break;
			case 3:
				//ic_l=(TIM2->CCR1-ic_l-ic_h);
			ic_h=HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1)-ic_l-ic_h;
			__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_1, TIM_ICPOLARITY_RISING);
				ic_flag++;
				break;
		}
	}
  /* USER CODE END TIM2_IRQn 0 */
  HAL_TIM_IRQHandler(&htim2);
  /* USER CODE BEGIN TIM2_IRQn 1 */

  /* USER CODE END TIM2_IRQn 1 */
}

特别注意一点,就是最后一次计算时要记得注意这个值是有时间基点的,不能直接拿来作为周期时间,要减去这个时间基点,一点粗心找半年啊!

四、pwm(记得待会做)

两种方法,输出比较,自带的pwm,
输出比较同一个定时器输出不同频率pwm
pwm模式一个定时器只能输出同频率的pwm
都可调占空比
注意输出比较最先输出有效电平

定时器的pwm

void pwm_init(void){
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	  GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_TimeBaseStructure.TIM_Period = 2000;
  TIM_TimeBaseStructure.TIM_Prescaler = 71;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 1000;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OC2Init(TIM3, &TIM_OCInitStructure);

  TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
	TIM_ARRPreloadConfig(TIM3, ENABLE);
	TIM_Cmd(TIM3, ENABLE);
}

下面是输出比较pwm
pwm高电平和低电平可以弄一个结构体封装,

void pwm_init(void){
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, 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);
	
	//GPIO_ResetBits(GPIOA, GPIO_Pin_6 | GPIO_Pin_7);
	
	TIM_TimeBaseStructure.TIM_Period = 0XFFFF;
  TIM_TimeBaseStructure.TIM_Prescaler = 71;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_Pulse = 0;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	
  TIM_OC1Init(TIM3, &TIM_OCInitStructure);
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);
	
  TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Disable);
	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Disable);
	
	TIM_Cmd(TIM3, ENABLE);
	 TIM_ITConfig(TIM3, TIM_IT_CC1|TIM_IT_CC2 , ENABLE);
}


void TIM3_IRQHandler(void)
{ 
  if(TIM_GetITStatus(TIM3, TIM_IT_CC1) == SET) 
  {
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
			TIM3->CCR1=TIM3->CCR1+half_cyc_o1;	
  }
	if(TIM_GetITStatus(TIM3, TIM_IT_CC2) == SET) 
  {
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
			TIM3->CCR2=TIM3->CCR2+half_cyc_o2;
		
  }
}

五、RTC

rtc闹钟中断和秒中断好像冲突,看有人说是因为里面有个是清全局中断,把闹钟中断优先级高于秒中断就行了,没试过,我把他们都放全局中断但还是一样,有闹钟没秒,还没发现为什么,只能先在闹钟中断里加上秒中断要做的事先解决再说。

初始rtc,外部低速晶振32768hz。

rtc的部分和总线部分速度不匹配,每次写入数据都要等上一次处理完。

void rtc_init(void){
	 NVIC_InitTypeDef NVIC_InitStructure;
	
	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
		//检测是否第一次开启,往备份区写数据校验
	 if (BKP_ReadBackupRegister(BKP_DR1) != 0x66bb)
  {
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
	 PWR_BackupAccessCmd(ENABLE);

  BKP_DeInit();
  RCC_LSEConfig(RCC_LSE_ON);
  while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
  {}

  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

  RCC_RTCCLKCmd(ENABLE);

  RTC_WaitForSynchro();

  RTC_WaitForLastTask();
//这里开中断
  RTC_ITConfig(RTC_IT_SEC, ENABLE);

  RTC_WaitForLastTask();

  RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */

  RTC_WaitForLastTask();
		
    RTC_SetCounter(23*3600+59*60+50);
  /* Wait until last write operation on RTC registers has finished */
  RTC_WaitForLastTask();

   // BKP_WriteBackupRegister(BKP_DR1, 0x66bb);
  }
  else
  {
    if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
    {
      printf("\r\n\n Power On Reset occurred....");
    }
    /* Check if the Pin Reset flag is set */
    else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)
    {
      printf("\r\n\n External Reset occurred....");
    }

    printf("\r\n No need to configure RTC....");
    /* Wait for RTC registers synchronization */
    RTC_WaitForSynchro();

    /* Enable the RTC Second */
    //RTC_ITConfig(RTC_IT_SEC, ENABLE);
    /* Wait until last write operation on RTC registers has finished */
    RTC_WaitForLastTask();
  }
  /* Clear reset flags */
  RCC_ClearFlag();
	//调整时间
	adjust_time();
}

调整时间的函数

void adjust_time(void){
	this_time=RTC_GetCounter();
	day=this_time/3600/24;
	now_time.HH=(this_time/3600)%24;
	now_time.MM=((this_time%3600)/60);
	now_time.SS=this_time%60;
}

中断
这里秒中断也会被闹钟中断吞,可以试试专门的那个闹钟中断

void RTC_IRQHandler(void)
{
  if (RTC_GetITStatus(RTC_IT_ALR) != RESET)
  {
    PWR_BackupAccessCmd(ENABLE);
    /* Clear Interrupt pending bit */
    RTC_ClearITPendingBit(RTC_FLAG_ALR);
		RTC_SetAlarm(5+RTC_GetCounter());
	//printf("闹钟中断%d",RTC_GetCounter());
			
  }
	
  if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
  {
  
//printf("秒中断%d",RTC_GetCounter());
    /* Clear Interrupt pending bit */
    RTC_ClearITPendingBit(RTC_FLAG_SEC);
  }
}

编码器接口模式

这里使用的是正交编码器,增量式。
主要看这一句

TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI1,TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);

TIM_ICPolarity_Rising,就是后面两个参数是写的ccip这个位,不是只捕获某个边沿的意思,只是反不反相的意思,TIM_ICPolarity_BothEdge在编码模式下是不能用的。所以这个模式只要是跳变沿都会有计数的。
还有编码器输出波形会有毛刺,即使经过了滤波也可能会有,最好能校准下。
有个疑惑:溢出或者下溢时计数器的计数值是会清零还是会怎样。
大佬的文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值