fast-livo硬件同步stm32代码学习
在看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数据
做到秒脉冲同步
更多推荐
所有评论(0)