在看stm32代码的时候,在想他是如何做的同步,仔细看了看程序,发现竟然逐渐看懂了。

首先分为基础知识,包含stm32的定时器,中断。当然,定时器对应那个IO口这些都可以直接从手册上找到,这个就不介绍了。

一.stm32定时器学习

       arr就是一个周期的最大计数值;psc就是一个分频器;cnt就是一个计数器,cnt到达arr之后就引发一次触发,或者说到了下一个周期。ccr就是一个比较值,如果向上计数,cnt小于ccr,那么就是低电平,如果cnt大于ccr,那么就是高电平。

      好了,那么看这两行代码

	TIM2_PWM_Init(999,7199); // 10 Hz    pin_A1       

 	TIM3_PWM_Init(9999,7199);	 // 1 Hz  pin_B5

       看tim2, arr= 999, psc= 7199, 那么stm32108c他的主频是72M,也就是72*10的6次方。现在通过分频器psc,分为了72*10的6次方 / (7199+1) = 10000,相当于是 一秒计数10000个数。

     再看


void TIM2_PWM_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_OCInitTypeDef TIM_OCInitStructure;
	

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 
	TIM_DeInit(TIM2);
 
 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //TIM_CH1  B6 pin out
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //??????
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);//???GPIO
 
   //???TIM4
	TIM_TimeBaseStructure.TIM_Period = arr; 
	TIM_TimeBaseStructure.TIM_Prescaler =psc; 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 
	
	//???TIM4 Channel1 PWM??	 
	TIM_OCInitStructure.TIM_Pulse = 50; //????????????????
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //???????:TIM????????2
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //??????
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //????:TIM???????
	TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
	TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);  //??TIM4?CCR2????????
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);  //??T??????????TIM4 OC2
	
	//???TIM4 Channel2 PWM??	 
//	TIM_OCInitStructure.TIM_Pulse = 500; //????????????????
//	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //???????:TIM????????2
// 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //??????
//	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //????:TIM???????
//	//TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
//	TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);  //??TIM4?CCR2????????
//	TIM_OC2Init(TIM4, &TIM_OCInitStructure);  //??T??????????TIM4 OC2

 	TIM_ARRPreloadConfig(TIM2, ENABLE);
	TIM_Cmd(TIM2, ENABLE);  //??TIM4
	


 //	TIM_SetCompare2(TIM2,50);	 // ccr  set pwm value
TIM_SetCompare2(TIM2,TIM2->ARR/2);
}

上升计数:TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

ccr的值 为TIM_SetCompare2(TIM2,TIM2->ARR/2);,也就是说ccr= arr/2,就是500。

 所以也就是一个周期技术导1000,其中一半是高电平,一半是低电平。

TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; 这个表示了非互补输出,所以channel1和channel2通道一致。 由于TIM_SetCompare2(TIM2,TIM2->ARR/2);所以 arr/2 到arr这个区间的计数就对应的是高电平。

2. pwm3初始化

    初始化为1HZ。


void TIM3_PWM_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
		NVIC_InitTypeDef NVIC_InitStructure;	

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//ʹ�ܶ�ʱ��3ʱ��
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //ʹ��GPIO�����AFIO���ù���ģ��ʱ��
	
	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3������ӳ��  TIM3_CH2->PB5    
 
   //���ø�����Ϊ�����������,���TIM3 CH2��PWM���岨��	GPIOB.5
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //�����������
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//��ʼ��GPIO
 
   //��ʼ��TIM3
	TIM_TimeBaseStructure.TIM_Period = arr; //��������һ�������¼�װ�����Զ���װ�ؼĴ������ڵ�ֵ
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //����������ΪTIMxʱ��Ƶ�ʳ�����Ԥ��Ƶֵ 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //����ʱ�ӷָ�:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM���ϼ���ģʽ
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //����TIM_TimeBaseInitStruct��ָ���IJ�����ʼ��TIMx��ʱ�������λ
	
	//��ʼ��TIM3 Channel2 PWMģʽ	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //ѡ��ʱ��ģʽ:TIM������ȵ���ģʽ2
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //�Ƚ����ʹ��
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //�������:TIM����Ƚϼ��Ը�
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //����Tָ���IJ�����ʼ������TIM3 OC2

	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //ʹ��TIM3��CCR2�ϵ�Ԥװ�ؼĴ���
 
	TIM_Cmd(TIM3, ENABLE);  //ʹ��TIM3
	
	TIM_SetCompare2(TIM3,TIM3->ARR/2);	

	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //ʹ��ָ����TIM3�ж�,���������ж�

	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3�ж�
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //��ռ���ȼ�0��
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //�����ȼ�3��
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨ����ʹ��
	NVIC_Init(&NVIC_InitStructure);  //����NVIC_InitStruct��ָ���IJ�����ʼ������NVIC�Ĵ���
}

3. 看一下中断

NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;

我们看到

time3的定时器输出channel2是:

	//��ʼ��TIM3 Channel2 PWMģʽ	 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //ѡ��ʱ��ģʽ:TIM������ȵ���ģʽ2
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //�Ƚ����ʹ��
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //�������:TIM����Ƚϼ��Ը�
	TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //����Tָ���IJ�����ʼ������TIM3 OC2

time2定时器输出是

	//???TIM4 Channel1 PWM??	 
	TIM_OCInitStructure.TIM_Pulse = 50; //????????????????
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //???????:TIM????????2
 	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //??????
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //????:TIM???????
	TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;
	TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);  //??TIM4?CCR2????????
	TIM_OC2Init(TIM2, &TIM_OCInitStructure);  //??T??????????TIM4 OC2

两个都是向上计数的话,那么一个是先高电平后低电平,一个是先低电平后高电平。

tim3配置了中断,那么一秒的中断次数和tim3定时器的频率是一致的。

        TIM2->CNT=TIM2->ARR/2;

经过这样一设置,那么两个在每一秒开始的时候的电平就是相同的。这样就确保了同步触发。


char value_1[100]="";
char value_2[100]="";
char value_time[10]="";

char test[100]="$GPRMC,004015,A,2812.0498,N,11313.1361,E,0.0,180.0,150122,3.9,W,A*";
void TIM3_IRQHandler(void)   //TIM3�ж�
{


		if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //���ָ����TIM�жϷ������:TIM �ж�Դ 
		{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //���TIMx���жϴ�����λ:TIM �ж�Դ 
		LED1=!LED1;
			
			//var_Exp �����ع�ʱ�������Ʋ���
		TIM2->CNT=TIM2->ARR/2;

		PCout(13)=0;
		}
		
		
		//global_time++;
		//shorttt=0;
		//sprintf(snum, "%06d", global_time); //������"000011D7"
		//snum[6]=0;
		//printf("$GPRMC,");
	  //printf(snum);
		//printf(".00,A,2237.496474,N,11356.089515,E,0.0,225.5,310518,2.3,W,A*23\n");
		

		
		//************************************* add *********************************************
		//UTCtime format: hhmmss
		
    if(ss<59){
				ss++;
		}else{
			  ss=0;
			 if(mm<59){
				 mm++;
			 }else{
				 mm=0;
				 if(hh<23){
					 hh++;
				 }else{
					 hh=0;
				 }
			 }
		}
		
    sprintf(value_2, "%s%02d%02d%02d%s", gprmcStr, hh, mm, ss, ".00,A,2237.496474,N,11356.089515,E,0.0,225.5,230520,2.3,W,A*");
		strcpy(value_1,value_2);
	  chckNum =checkNum(value_1);
	  sprintf(chckNumChar, "%02X", chckNum);
		printf("%s", value_2);
    printf("%s\n", chckNumChar);
	 
		
	  //**********************************************************************************

		/**
		chckNum=checkNum(test);	
	  sprintf(chckNumChar, "%02X", chckNum);
    printf("%s\n", chckNumChar);
    */
}

print函数就是串口输出的。

LED1貌似没啥用

学到的知识

1.两个定时器如何保持同步触发

    就是用cnt来控制

2.如何发送gprc数据

   做到秒脉冲同步

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐