У меня есть, на мой взгляд, интересная задачка (хотя я новичок в МК, может быть, преувеличиваю), над которой я изрядно поломал мозг, но так и не решил.
Есть устройство (на основе STM32f107), которое синхронизируется от GPS и тактируется от высокостабильного источника частоты.
После того, как прибор засинхронизировался, таймер (TIM4) в режиме Input Capture начинает захватывать 1PPS от GPS в третьем канале и 1PPS от того же GPS в четвёртом канале, дальше из одного значения вычитается другое и получаем... (2103 плюс-минус 3) такта, это, примерно, 29 мкс. Снимая таким образом показания каждую секунду, получаем одно и то же значение.
Вопрос возникает сам собой — откуда берутся эти 2103 тактов?
Если нужно будет, я выложу весь код.
Инициализация таймера:
CODE
void TIM4_Alarm_Config (void)
{
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // подача тактов на TIM4 от шины тактирования APB1
TIM4->PSC = 1 - 1; // Предварительный делитель: значения счетчика будут инкрементироваться с частотой 35 MГц
TIM4->ARR = 65534 - 1; // Максимальное значение, до которого будет считать таймер, равно 65535
// канал 3 (1Гц)
TIM4->CCMR2 |= TIM_CCMR2_CC3S_0; // выбор активного входа, канал 3 TIM4_CH3 (PB8) <<------ подать на этот канал 1Гц
TIM4->CCER &=~ TIM_CCER_CC3P; // срабатывание по переднему фронту
TIM4->CCMR2 &=~ TIM_CCMR2_IC3PSC; // захват каждого импульса
// TIM4->CCER |= TIM_CCER_CC3E; // включить захват из счётчика // в EXTI1
TIM4->DIER |= TIM_DIER_CC3IE; // включение прерывания от захвата
// канал 4 (1PPS)
TIM4->CCMR2 |= TIM_CCMR2_CC4S_0; // выбор активного входа, канал 4 TIM4_CH4 (PB9) <<------ подать на этот канал 1PPS
TIM4->CCER &=~ TIM_CCER_CC4P; // срабатывание по переднему фронту
TIM4->CCMR2 &=~ TIM_CCMR2_IC4PSC; // захват каждого импульса
// TIM4->CCER |= TIM_CCER_CC4E; // включить захват из счётчика // в EXTI1
TIM4->DIER |= TIM_DIER_CC4IE; // включение прерывания от захвата
}
{
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // подача тактов на TIM4 от шины тактирования APB1
TIM4->PSC = 1 - 1; // Предварительный делитель: значения счетчика будут инкрементироваться с частотой 35 MГц
TIM4->ARR = 65534 - 1; // Максимальное значение, до которого будет считать таймер, равно 65535
// канал 3 (1Гц)
TIM4->CCMR2 |= TIM_CCMR2_CC3S_0; // выбор активного входа, канал 3 TIM4_CH3 (PB8) <<------ подать на этот канал 1Гц
TIM4->CCER &=~ TIM_CCER_CC3P; // срабатывание по переднему фронту
TIM4->CCMR2 &=~ TIM_CCMR2_IC3PSC; // захват каждого импульса
// TIM4->CCER |= TIM_CCER_CC3E; // включить захват из счётчика // в EXTI1
TIM4->DIER |= TIM_DIER_CC3IE; // включение прерывания от захвата
// канал 4 (1PPS)
TIM4->CCMR2 |= TIM_CCMR2_CC4S_0; // выбор активного входа, канал 4 TIM4_CH4 (PB9) <<------ подать на этот канал 1PPS
TIM4->CCER &=~ TIM_CCER_CC4P; // срабатывание по переднему фронту
TIM4->CCMR2 &=~ TIM_CCMR2_IC4PSC; // захват каждого импульса
// TIM4->CCER |= TIM_CCER_CC4E; // включить захват из счётчика // в EXTI1
TIM4->DIER |= TIM_DIER_CC4IE; // включение прерывания от захвата
}
Прерывание от таймера:
CODE
void TIM4_IRQHandler(void)
{
if (TIM4->SR&TIM_SR_CC3IF) // 1Гц
{
TIM4->SR &=~ TIM_SR_CC3IF; // очиcтка флага прерывания
count1 = TIM4->CCR3; // считываем значение счётчика в переменную count1, если выставлен флаг прерывания
}
if (TIM4->SR&TIM_SR_CC4IF) // 1PPS
{
TIM4->SR &=~ TIM_SR_CC4IF; // очиcтка флага прерывания
count2 = TIM4->CCR4; // считываем значение счётчика в переменную count1, если выставлен флаг прерывания
}
if((count1>0)&&(count2>0))
{
if(count1>count2)
{
razn = count1 - count2;
}
if(count2>count1)
{
razn = count2 - count1;
}
count1=0;
count2=0;
if (razn >(bias+1000)){razn = 65534 - razn;}
// if(bias>razn)
// {
rash = razn + 100;// - bias; // добавил биас rash - unsigned int
// }
// if(razn>bias)
// {
// rash = razn - bias;
// }
//while (!(USART2->SR & USART_SR_TXE)) {} // Ждать освобождения буфера.
//USART2->DR=rash;
union {
unsigned int Mylong2;
char buf3[2]; // рассогласование в микросекундах
}MyUnion2;
MyUnion2.Mylong2 = rash;
while (!(USART2->SR & USART_SR_TXE)) {} // Ждать освобождения буфера.
USART2->DR=MyUnion2.buf3[1]; // рассогласование в микросекундах
while (!(USART2->SR & USART_SR_TXE)) {} // Ждать освобождения буфера.
USART2->DR=MyUnion2.buf3[0];
if (rash<90)
{GPIOA->BSRR |= GPIO_BSRR_BS7;} // генерация импульса, который подаётся на GPIOA_PIN6 (PA7), <<----- импульс сигнализации}
if (rash>110)
{GPIOA->BSRR |= GPIO_BSRR_BS7;} // генерация импульса, который подаётся на GPIOA_PIN6 (PA7), <<----- импульс сигнализации}
}
}
{
if (TIM4->SR&TIM_SR_CC3IF) // 1Гц
{
TIM4->SR &=~ TIM_SR_CC3IF; // очиcтка флага прерывания
count1 = TIM4->CCR3; // считываем значение счётчика в переменную count1, если выставлен флаг прерывания
}
if (TIM4->SR&TIM_SR_CC4IF) // 1PPS
{
TIM4->SR &=~ TIM_SR_CC4IF; // очиcтка флага прерывания
count2 = TIM4->CCR4; // считываем значение счётчика в переменную count1, если выставлен флаг прерывания
}
if((count1>0)&&(count2>0))
{
if(count1>count2)
{
razn = count1 - count2;
}
if(count2>count1)
{
razn = count2 - count1;
}
count1=0;
count2=0;
if (razn >(bias+1000)){razn = 65534 - razn;}
// if(bias>razn)
// {
rash = razn + 100;// - bias; // добавил биас rash - unsigned int
// }
// if(razn>bias)
// {
// rash = razn - bias;
// }
//while (!(USART2->SR & USART_SR_TXE)) {} // Ждать освобождения буфера.
//USART2->DR=rash;
union {
unsigned int Mylong2;
char buf3[2]; // рассогласование в микросекундах
}MyUnion2;
MyUnion2.Mylong2 = rash;
while (!(USART2->SR & USART_SR_TXE)) {} // Ждать освобождения буфера.
USART2->DR=MyUnion2.buf3[1]; // рассогласование в микросекундах
while (!(USART2->SR & USART_SR_TXE)) {} // Ждать освобождения буфера.
USART2->DR=MyUnion2.buf3[0];
if (rash<90)
{GPIOA->BSRR |= GPIO_BSRR_BS7;} // генерация импульса, который подаётся на GPIOA_PIN6 (PA7), <<----- импульс сигнализации}
if (rash>110)
{GPIOA->BSRR |= GPIO_BSRR_BS7;} // генерация импульса, который подаётся на GPIOA_PIN6 (PA7), <<----- импульс сигнализации}
}
}