реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Closed TopicStart new topic
> stm32 + абсолютный энкодер
Alexsandr000
сообщение Oct 20 2014, 13:56
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 97
Регистрация: 23-10-12
Пользователь №: 74 054



Здравствуйте уважаемые форумчане!

Хотел спросить у вас совета. Есть абсолютный энкодер с 1024 отсчетами угла поворота и stm32 работающий на 72 МГц, данные с энкодера передаются на МК через 10 выводов. Вал энкодера соединен с валом двигателя через шестерню с передаточным числом 1/7. Была написана программа для определения угла поворота и передачи его на ПК через UART. Тут возникло две проблемы:
1. Данные на ПК иногда передаются не корректно;
2. Как преобразовать угол поворота энкодера в угол поворота двигателя.
вот код:
CODE
#include "main.h"
//////////////////////////////////////////////////////////////////////
int main(void){
init_timer();
init_gpio();
init_clock();
init_uart();
for(i = 0; i < 200000; i++);
if(!RCC_CFGR_SWS_HSE){ GPIOA->ODR ^= GPIO_Pin_0; }
Usart2_Send_String("Hello, world!"); //Передаем строку, сообщающую о готовности микроконтроллера к обмену данными
NVIC_SetPriority(TIM3_IRQn, 1);
while(1){
if(State == 1){
NVIC_DisableIRQ(TIM3_IRQn);
State = 0;
D0 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
D1 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11);
D2 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10);
D3 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_9);
D4 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8);
D5 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_15);
D6 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14);
D7 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
D8 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);
D9 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
pos = D0 | (D1 << 1) | (D2 << 2) | (D3 << 3) | (D4 << 4) | (D5 << 5) | (D6 << 6) | (D7 << 7) | (D8 << 8) | (D9 << 9);

if(pos <= convert.INT){
while(!(USART2->SR & USART_SR_TC)); //Проверяем установку флага TC - завершения предыдущей передачи
USART_SendData(USART2, convert.CHAR[0]);
for(i = 0; i < 100; i++);
while(!(USART2->SR & USART_SR_TC)); //Проверяем установку флага TC - завершения предыдущей передачи
USART_SendData(USART2, convert.CHAR[1]);
pos = convert.INT;
}
NVIC_EnableIRQ(TIM3_IRQn);
}
for(i = 0; i < 100000; i++);
}
return 0;
}
void init_gpio(void){
GPIO_InitTypeDef gpio_cfgA, gpio_cfgB, gpio_cfgLED;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_StructInit(&gpio_cfgA);
GPIO_StructInit(&gpio_cfgB);
GPIO_StructInit(&gpio_cfgLED);
gpio_cfgA.GPIO_Mode = GPIO_Mode_IN_FLOATING; //GPIO_Mode_Out_PP;
gpio_cfgA.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_11| GPIO_Pin_10 | GPIO_Pin_9 | GPIO_Pin_8 | GPIO_Pin_6;
gpio_cfgA.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio_cfgA);
gpio_cfgB.GPIO_Mode = GPIO_Mode_IN_FLOATING; //GPIO_Mode_Out_PP;
gpio_cfgB.GPIO_Pin = GPIO_Pin_15 | GPIO_Pin_14| GPIO_Pin_13 | GPIO_Pin_12 | GPIO_Pin_11;
gpio_cfgB.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_cfgB);
gpio_cfgLED.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_cfgLED.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
gpio_cfgLED.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA, &gpio_cfgLED);
}
void init_timer(){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); /* Не забываем затактировать таймер */
TIM_TimeBaseInitTypeDef timer_base;
TIM_TimeBaseStructInit(&timer_base);
timer_base.TIM_Prescaler = 720 - 1; /* Делитель учитывается как TIM_Prescaler + 1, поэтому отнимаем 1 */
timer_base.TIM_Period = 1;
TIM_TimeBaseInit(TIM3, &timer_base);
/* Настраиваем захват сигнала: - канал: 1 - счёт: по нарастанию - источник: напрямую со входа - делитель: отключен - фильтр: отключен */
TIM_ICInitTypeDef timer_ic;
timer_ic.TIM_Channel = TIM_Channel_1;
timer_ic.TIM_ICPolarity = TIM_ICPolarity_BothEdge; //TIM_ICPolarity_Rising;
timer_ic.TIM_ICSelection = TIM_ICSelection_DirectTI;
timer_ic.TIM_ICPrescaler = TIM_ICPSC_DIV1;
timer_ic.TIM_ICFilter = 2;
TIM_PWMIConfig(TIM3, &timer_ic); /* Эта функция настроит канал 1 для захвата периода, а канал 2 - для захвата заполнения. */
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); /* Выбираем источник для триггера: вход 1 (PA6) */
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); /* По событию от триггера счётчик будет сбрасываться. */
TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable); /* Включаем события от триггера */
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE); /* Разрешаем таймеру генерировать прерывание по захвату */
TIM_Cmd(TIM3, ENABLE); /* Включаем таймер */
NVIC_EnableIRQ(TIM3_IRQn); /* Разрешаем прерывания таймера TIM3 */
}
void TIM3_IRQHandler(){
if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET) {
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1); /* Даём знать, что обработали прерывание */
State = 1;
GPIOA->ODR ^= GPIO_Pin_1;
}
}


Заранее спасибо!!!

Сообщение отредактировал IgorKossak - Oct 20 2014, 14:13
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!


--------------------
Go to the top of the page
 
+Quote Post
_3m
сообщение Oct 20 2014, 14:07
Сообщение #2


Знающий
****

Группа: Участник
Сообщений: 745
Регистрация: 28-12-06
Пользователь №: 23 960



Цитата(Alexsandr000 @ Oct 20 2014, 17:56) *
Хотел спросить у вас совета. Есть абсолютный энкодер с 1024 отсчетами угла поворота и stm32 работающий на 72 МГц, данные с энкодера передаются на МК через 10 выводов.

Все 10 бит с энкодера необходимо считывать одновременно (одной командой чтения) потому что в процессе чтения код может измениться и в таком случае побитовое чтение даст неправильный результат.
Go to the top of the page
 
+Quote Post
net
сообщение Oct 20 2014, 16:21
Сообщение #3


Знающий
****

Группа: Свой
Сообщений: 858
Регистрация: 9-08-04
Пользователь №: 473



QUOTE (_3m @ Oct 20 2014, 18:07) *
Все 10 бит с энкодера необходимо считывать одновременно (одной командой чтения) потому что в процессе чтения код может измениться и в таком случае побитовое чтение даст неправильный результат.

и до тех пор пока два раза не станет одинаковыми smile3046.gif
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Oct 20 2014, 18:30
Сообщение #4


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(net @ Oct 20 2014, 18:21) *
и до тех пор пока два раза не станет одинаковыми smile3046.gif

Я бы сказал более обще: применить к получаемым данным подходящий алгоритм фильтрации.
А для конкретного примера распиновки порекомендовал бы еще не собирать данные побитово, а прочитать сразу все содержимое портов A и B и лишь потом рассортировать биты.
Go to the top of the page
 
+Quote Post
Alexsandr000
сообщение Oct 21 2014, 05:14
Сообщение #5


Частый гость
**

Группа: Участник
Сообщений: 97
Регистрация: 23-10-12
Пользователь №: 74 054



Это я сделал
CODE
#include "main.h"
//////////////////////////////////////////////////////////////////////
int main(void){
init_timer();
init_gpio();
init_clock();
init_uart();
for(i = 0; i < 200000; i++);
if(!RCC_CFGR_SWS_HSE){ GPIOA->ODR ^= GPIO_Pin_0; }
Usart2_Send_String("Hello, world!"); //Передаем строку, сообщающую о готовности микроконтроллера к обмену данными
NVIC_SetPriority(TIM3_IRQn, 1);
while(1){
if(State == 1){
NVIC_DisableIRQ(TIM3_IRQn);
State = 0;
PA = GPIOA_IDR;
PB = GPIOB_IDR;
D0 = (PA & 0b0000000000100000) >> 6;
D1 = (PA & 0b0000010000000000) >> 11;
D2 = (PA & 0b0000001000000000) >> 10;
D3 = (PA & 0b0000000100000000) >> 9;
D4 = (PA & 0b0000000010000000) >> 8;
D5 = (PB & 0b1000000000000000) >> 15;
D6 = (PB & 0b0100000000000000) >> 14;
D7 = (PB & 0b0010000000000000) >> 13;
D8 = (PB & 0b0001000000000000) >> 12;
D9 = (PB & 0b0000100000000000) >> 11;
/*
D0 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
D1 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11);
D2 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_10);
D3 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_9);
D4 = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8);
D5 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_15);
D6 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14);
D7 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);
D8 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);
D9 = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
*/
pos = D0 | (D1 << 1) | (D2 << 2) | (D3 << 3) | (D4 << 4) | (D5 << 5) | (D6 << 6) | (D7 << 7) | (D8 << 8);

if(pos <= convert.INT){
while(!(USART2->SR & USART_SR_TC)); //Проверяем установку флага TC - завершения предыдущей передачи
USART_SendData(USART2, convert.CHAR[0]);
for(i = 0; i < 100; i++);
while(!(USART2->SR & USART_SR_TC)); //Проверяем установку флага TC - завершения предыдущей передачи
USART_SendData(USART2, convert.CHAR[1]);
pos = convert.INT;
}
NVIC_EnableIRQ(TIM3_IRQn);
}
for(i = 0; i < 100000; i++);
}
return 0;
}
void init_gpio(void){
GPIO_InitTypeDef gpio_cfgA, gpio_cfgB, gpio_cfgLED;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_StructInit(&gpio_cfgA);
GPIO_StructInit(&gpio_cfgB);
GPIO_StructInit(&gpio_cfgLED);
gpio_cfgA.GPIO_Mode = GPIO_Mode_IN_FLOATING; //GPIO_Mode_Out_PP;
gpio_cfgA.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_11| GPIO_Pin_10 | GPIO_Pin_9 | GPIO_Pin_8 | GPIO_Pin_6;
gpio_cfgA.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio_cfgA);
gpio_cfgB.GPIO_Mode = GPIO_Mode_IN_FLOATING; //GPIO_Mode_Out_PP;
gpio_cfgB.GPIO_Pin = GPIO_Pin_15 | GPIO_Pin_14| GPIO_Pin_13 | GPIO_Pin_12 | GPIO_Pin_11;
gpio_cfgB.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_cfgB);
gpio_cfgLED.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_cfgLED.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
gpio_cfgLED.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA, &gpio_cfgLED);
}
void init_timer(){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); /* Не забываем затактировать таймер */
TIM_TimeBaseInitTypeDef timer_base;
TIM_TimeBaseStructInit(&timer_base);
timer_base.TIM_Prescaler = 720 - 1; /* Делитель учитывается как TIM_Prescaler + 1, поэтому отнимаем 1 */
timer_base.TIM_Period = 1;
TIM_TimeBaseInit(TIM3, &timer_base);
/* Настраиваем захват сигнала: - канал: 1 - счёт: по нарастанию - источник: напрямую со входа - делитель: отключен - фильтр: отключен */
TIM_ICInitTypeDef timer_ic;
timer_ic.TIM_Channel = TIM_Channel_1;
timer_ic.TIM_ICPolarity = TIM_ICPolarity_BothEdge; //TIM_ICPolarity_Rising;
timer_ic.TIM_ICSelection = TIM_ICSelection_DirectTI;
timer_ic.TIM_ICPrescaler = TIM_ICPSC_DIV1;
timer_ic.TIM_ICFilter = 2;
TIM_PWMIConfig(TIM3, &timer_ic); /* Эта функция настроит канал 1 для захвата периода, а канал 2 - для захвата заполнения. */
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); /* Выбираем источник для триггера: вход 1 (PA6) */
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); /* По событию от триггера счётчик будет сбрасываться. */
TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable); /* Включаем события от триггера */
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE); /* Разрешаем таймеру генерировать прерывание по захвату */
TIM_Cmd(TIM3, ENABLE); /* Включаем таймер */
NVIC_EnableIRQ(TIM3_IRQn); /* Разрешаем прерывания таймера TIM3 */
}
void TIM3_IRQHandler(){
if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET) {
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1); /* Даём знать, что обработали прерывание */
State = 1;
GPIOA->ODR ^= GPIO_Pin_1;
}
}


Сообщение отредактировал Alexsandr000 - Oct 21 2014, 05:17


--------------------
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Oct 21 2014, 07:07
Сообщение #6


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(Alexsandr000 @ Oct 21 2014, 07:14) *
Это я сделал

Помогло как-то?
Go to the top of the page
 
+Quote Post
net
сообщение Oct 21 2014, 07:35
Сообщение #7


Знающий
****

Группа: Свой
Сообщений: 858
Регистрация: 9-08-04
Пользователь №: 473



QUOTE (KnightIgor @ Oct 20 2014, 22:30) *
Я бы сказал более обще: применить к получаемым данным подходящий алгоритм фильтрации.
А для конкретного примера распиновки порекомендовал бы еще не собирать данные побитово, а прочитать сразу все содержимое портов A и B и лишь потом рассортировать биты.

я имел ввиду что считывание может попасть на момент переключения - если запись в регистр данных с устройства не стробируется
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Oct 21 2014, 09:05
Сообщение #8


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(net @ Oct 21 2014, 09:35) *
я имел ввиду что считывание может попасть на момент переключения - если запись в регистр данных с устройства не стробируется

Вопрос в том, каково соотношение частот переключения и опроса. Можно ограничиться конкретным случаем и решить, что соотношение разительное, и процессор сто раз успеет. Вполне допустимый подход. Можно, однако, подойти обще и применить фильтрацию, которая исключит сбои и в случае, если завтра моторчик шустро раскрутится, а процессор будет напевать MP3 песенку. Мне в этой связи вспоминается статья (кажется на Хабре) об упавшей ракете Ariane: когда стали разбираться, нашли, что самоликвидация произошла из-за старого участка кода управления, который посчитал более выское ускорение модифицированных двигателей ракеты отклонением от нормы.

Сообщение отредактировал KnightIgor - Oct 21 2014, 09:06
Go to the top of the page
 
+Quote Post
Alexsandr000
сообщение Oct 21 2014, 09:14
Сообщение #9


Частый гость
**

Группа: Участник
Сообщений: 97
Регистрация: 23-10-12
Пользователь №: 74 054



сделал так, но теперь не пойму почему данные с UART бьются
CODE
#include "main.h"
//////////////////////////////////////////////////////////////////////
int main(void){
init_timer();
init_gpio();
init_clock();
init_uart();
for(i = 0; i < 200000; i++);
if(!RCC_CFGR_SWS_HSE){ GPIOA->ODR ^= GPIO_Pin_0; }
Usart2_Send_String("Hello, world!"); //Передаем строку, сообщающую о готовности микроконтроллера к обмену данными
NVIC_SetPriority(TIM3_IRQn, 1);
while(1){
if(State == 2){
NVIC_DisableIRQ(TIM3_IRQn);
State = 0;
pos = pos_1;
if(pos != old_pos){
if(convert.INT >= 7168 || convert.INT <= -7160) {
convert.INT = 0;
while(!(USART2->SR & USART_SR_TC)); //Проверяем установку флага TC - завершения предыдущей передачи
USART_SendData(USART2, convert.CHAR[0]);
for(i = 0; i < 100; i++);
while(!(USART2->SR & USART_SR_TC)); //Проверяем установку флага TC - завершения предыдущей передачи
USART_SendData(USART2, convert.CHAR[1]);
}
else{
if((old_pos - pos) > 0){
convert.INT = convert.INT - pos;
}
else{
convert.INT = convert.INT + pos;
}
while(!(USART2->SR & USART_SR_TC)); //Проверяем установку флага TC - завершения предыдущей передачи
USART_SendData(USART2, convert.CHAR[0]);
for(i = 0; i < 100; i++);
while(!(USART2->SR & USART_SR_TC)); //Проверяем установку флага TC - завершения предыдущей передачи
USART_SendData(USART2, convert.CHAR[1]);
}
old_pos = pos;
}

NVIC_EnableIRQ(TIM3_IRQn);
}
for(i = 0; i < 100000; i++);
}
return 0;
}
void init_gpio(void){
GPIO_InitTypeDef gpio_cfgA, gpio_cfgB, gpio_cfgLED;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_StructInit(&gpio_cfgA);
GPIO_StructInit(&gpio_cfgB);
GPIO_StructInit(&gpio_cfgLED);
gpio_cfgA.GPIO_Mode = GPIO_Mode_IN_FLOATING; //GPIO_Mode_Out_PP;
gpio_cfgA.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_11| GPIO_Pin_10 | GPIO_Pin_9 | GPIO_Pin_8 | GPIO_Pin_6;
gpio_cfgA.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio_cfgA);
gpio_cfgB.GPIO_Mode = GPIO_Mode_IN_FLOATING; //GPIO_Mode_Out_PP;
gpio_cfgB.GPIO_Pin = GPIO_Pin_15 | GPIO_Pin_14| GPIO_Pin_13 | GPIO_Pin_12 | GPIO_Pin_11;
gpio_cfgB.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_cfgB);
gpio_cfgLED.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_cfgLED.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
gpio_cfgLED.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA, &gpio_cfgLED);
}
void init_timer(){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); /* Не забываем затактировать таймер */
TIM_TimeBaseInitTypeDef timer_base;
TIM_TimeBaseStructInit(&timer_base);
timer_base.TIM_Prescaler = 72 - 1; /* Делитель учитывается как TIM_Prescaler + 1, поэтому отнимаем 1 */
timer_base.TIM_Period = 10;
TIM_TimeBaseInit(TIM3, &timer_base);
/* Настраиваем захват сигнала: - канал: 1 - счёт: по нарастанию - источник: напрямую со входа - делитель: отключен - фильтр: отключен */
TIM_ICInitTypeDef timer_ic;
timer_ic.TIM_Channel = TIM_Channel_1;
timer_ic.TIM_ICPolarity = TIM_ICPolarity_BothEdge; //TIM_ICPolarity_Rising;
timer_ic.TIM_ICSelection = TIM_ICSelection_DirectTI;
timer_ic.TIM_ICPrescaler = TIM_ICPSC_DIV1;
timer_ic.TIM_ICFilter = 2;
TIM_PWMIConfig(TIM3, &timer_ic); /* Эта функция настроит канал 1 для захвата периода, а канал 2 - для захвата заполнения. */
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); /* Выбираем источник для триггера: вход 1 (PA6) */
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); /* По событию от триггера счётчик будет сбрасываться. */
TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable); /* Включаем события от триггера */
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE); /* Разрешаем таймеру генерировать прерывание по захвату */
TIM_Cmd(TIM3, ENABLE); /* Включаем таймер */
NVIC_EnableIRQ(TIM3_IRQn); /* Разрешаем прерывания таймера TIM3 */
}
void TIM3_IRQHandler(){
if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET) {
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1); /* Даём знать, что обработали прерывание */
if(State == 0){
State = 1;
PA = GPIOA->IDR;
PB = GPIOB->IDR;
D0 = (~PA & 0b0000000000100000) >> 6;
D1 = (~PA & 0b0000010000000000) >> 11;
D2 = (~PA & 0b0000001000000000) >> 10;
D3 = (~PA & 0b0000000100000000) >> 9;
D4 = (~PA & 0b0000000010000000) >> 8;
D5 = (~PB & 0b1000000000000000) >> 15;
D6 = (~PB & 0b0100000000000000) >> 14;
D7 = (~PB & 0b0010000000000000) >> 13;
D8 = (~PB & 0b0001000000000000) >> 12;
D9 = (~PB & 0b0000100000000000) >> 11;
pos_1 = D0 | (D1 << 1) | (D2 << 2) | (D3 << 3) | (D4 << 4) | (D5 << 5) | (D6 << 6) | (D7 << 7) | (D8 << 8) | (D9 << 9);
}
else if(State == 1){
PA2 = GPIOA->IDR;
PB2 = GPIOB->IDR;
D0 = (~PA2 & 0b0000000000100000) >> 6;
D1 = (~PA2 & 0b0000010000000000) >> 11;
D2 = (~PA2 & 0b0000001000000000) >> 10;
D3 = (~PA2 & 0b0000000100000000) >> 9;
D4 = (~PA2 & 0b0000000010000000) >> 8;
D5 = (~PB2 & 0b1000000000000000) >> 15;
D6 = (~PB2 & 0b0100000000000000) >> 14;
D7 = (~PB2 & 0b0010000000000000) >> 13;
D8 = (~PB2 & 0b0001000000000000) >> 12;
D9 = (~PB2 & 0b0000100000000000) >> 11;
pos_2 = D0 | (D1 << 1) | (D2 << 2) | (D3 << 3) | (D4 << 4) | (D5 << 5) | (D6 << 6) | (D7 << 7) | (D8 << 8) | (D9 << 9);
if(pos_2 == pos_1){
State = 2;
}
else{
State = 0;
}
}
GPIOA->ODR ^= GPIO_Pin_1;
}
}


--------------------
Go to the top of the page
 
+Quote Post
net
сообщение Oct 21 2014, 10:41
Сообщение #10


Знающий
****

Группа: Свой
Сообщений: 858
Регистрация: 9-08-04
Пользователь №: 473



QUOTE (KnightIgor @ Oct 21 2014, 13:05) *
Вопрос в том, каково соотношение частот переключения и опроса. Можно ограничиться конкретным случаем и решить, что соотношение разительное, и процессор сто раз успеет. Вполне допустимый подход.

нееее - так нельзя - потому как будет сбоить один раз в год, но в самымй неподходящий момент


Go to the top of the page
 
+Quote Post
Alexsandr000
сообщение Oct 21 2014, 10:58
Сообщение #11


Частый гость
**

Группа: Участник
Сообщений: 97
Регистрация: 23-10-12
Пользователь №: 74 054



Цитата(net @ Oct 21 2014, 14:41) *
нееее - так нельзя - потому как будет сбоить один раз в год, но в самымй неподходящий момент

И сбоит, каждые 2-3 периода


--------------------
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Oct 21 2014, 17:53
Сообщение #12


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(Alexsandr000 @ Oct 21 2014, 16:58) *
И сбоит, каждые 2-3 периода

Вы не в разных прерываниях по таймеру читайте два раза, а прямо подряд, в одном прерывании:
Код
uint16_t ReadEncoder()
{
    uint16_t PA, PB;
    PA = ~GPIOA->IDR;
    PB = ~GPIOB->IDR;
    return 0
        | ((PA & 0b0000000000100000) >> (6 - 0))
        | ((PA & 0b0000010000000000) >> (11 - 1))
        | ((PA & 0b0000001000000000) >> (10 - 2))
        | ((PA & 0b0000000100000000) >> (9 - 3))
        | ((PA & 0b0000000010000000) >> (8 - 4))
        | ((PB & 0b1000000000000000) >> (15 - 5))
        | ((PB & 0b0100000000000000) >> (14 - 6))
        | ((PB & 0b0010000000000000) >> (13 - 7))
        | ((PB & 0b0001000000000000) >> (12 - 8))
        | ((PB & 0b0000100000000000) >> (11 - 9));
}


И в прерывании:
Код
void TIM3_IRQHandler()
{
    uint16_t enc1, enc2;
    if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
        do
        {
            enc1 = ReadEncoder();
            enc2 = ReadEncoder();
        } while (enc1!=enc2);
        // здесь используем правильное значение enc1.
    }
}


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
KnightIgor
сообщение Oct 22 2014, 07:29
Сообщение #13


Знающий
****

Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725



Цитата(net @ Oct 21 2014, 12:41) *
нееее - так нельзя - потому как будет сбоить один раз в год, но в самымй неподходящий момент

Именно тот случай, когда фраза вырывается из контекста. Там дальше была-таки рекомендация применить общий подход с фильтрацией.
А сбой раз в год гарантирован в любом случае: сбой флэш, бросок питания, и т.п.
Go to the top of the page
 
+Quote Post
Alexsandr000
сообщение Oct 22 2014, 08:13
Сообщение #14


Частый гость
**

Группа: Участник
Сообщений: 97
Регистрация: 23-10-12
Пользователь №: 74 054



Огромное всем спасибо!!!
Ну сбоить будет в любом случае, это не ПЛИС. Я думаю отправлять данные сразу на UART, а фильтровать на ПК.
Только не совсем пока понятно как отфильтровывать. При вращении периодически сбоит, но я думаю с МК уже ничего не выжмешь. Кстати код:
CODE
#include "main.h"
//////////////////////////////////////////////////////////////////////
int main(void){
init_timer();
init_gpio();
init_clock();
init_uart();
for(i = 0; i < 200000; i++);
if(!RCC_CFGR_SWS_HSE){ GPIOA->ODR ^= GPIO_Pin_0; }
Usart2_Send_String("Hello, world!"); //Передаем строку, сообщающую о готовности микроконтроллера к обмену данными
NVIC_SetPriority(TIM3_IRQn, 1);
while(1){
if(State == 1){
NVIC_DisableIRQ(TIM3_IRQn);
State = 0;
//pos = //pos_1;
if(pos != old_pos){
convert.INT = pos;
while(!(USART2->SR & USART_SR_TC)); //Проверяем установку флага TC - завершения предыдущей передачи
USART_SendData(USART2, convert.CHAR[0]);
for(i = 0; i < 100; i++);
while(!(USART2->SR & USART_SR_TC)); //Проверяем установку флага TC - завершения предыдущей передачи
USART_SendData(USART2, convert.CHAR[1]);
old_pos = pos;
}
NVIC_EnableIRQ(TIM3_IRQn);
}
for(i = 0; i < 100000; i++);
}
return 0;
}
void init_gpio(void){
GPIO_InitTypeDef gpio_cfgA, gpio_cfgB, gpio_cfgLED;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_StructInit(&gpio_cfgA);
GPIO_StructInit(&gpio_cfgB);
GPIO_StructInit(&gpio_cfgLED);
gpio_cfgA.GPIO_Mode = GPIO_Mode_IN_FLOATING; //GPIO_Mode_Out_PP;
gpio_cfgA.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_11| GPIO_Pin_10 | GPIO_Pin_9 | GPIO_Pin_8 | GPIO_Pin_6;
gpio_cfgA.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio_cfgA);
gpio_cfgB.GPIO_Mode = GPIO_Mode_IN_FLOATING; //GPIO_Mode_Out_PP;
gpio_cfgB.GPIO_Pin = GPIO_Pin_15 | GPIO_Pin_14| GPIO_Pin_13 | GPIO_Pin_12 | GPIO_Pin_11;
gpio_cfgB.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_cfgB);
gpio_cfgLED.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_cfgLED.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
gpio_cfgLED.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOA, &gpio_cfgLED);
}
void init_timer(){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); /* Не забываем затактировать таймер */
TIM_TimeBaseInitTypeDef timer_base;
TIM_TimeBaseStructInit(&timer_base);
timer_base.TIM_Prescaler = 72 - 1; /* Делитель учитывается как TIM_Prescaler + 1, поэтому отнимаем 1 */
timer_base.TIM_Period = 10;
TIM_TimeBaseInit(TIM3, &timer_base);
/* Настраиваем захват сигнала: - канал: 1 - счёт: по нарастанию - источник: напрямую со входа - делитель: отключен - фильтр: отключен */
TIM_ICInitTypeDef timer_ic;
timer_ic.TIM_Channel = TIM_Channel_1;
timer_ic.TIM_ICPolarity = TIM_ICPolarity_Rising;
timer_ic.TIM_ICSelection = TIM_ICSelection_DirectTI;
timer_ic.TIM_ICPrescaler = TIM_ICPSC_DIV1;
timer_ic.TIM_ICFilter = 20;
TIM_PWMIConfig(TIM3, &timer_ic); /* Эта функция настроит канал 1 для захвата периода, а канал 2 - для захвата заполнения. */
TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1); /* Выбираем источник для триггера: вход 1 (PA6) */
TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset); /* По событию от триггера счётчик будет сбрасываться. */
TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable); /* Включаем события от триггера */
TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE); /* Разрешаем таймеру генерировать прерывание по захвату */
TIM_Cmd(TIM3, ENABLE); /* Включаем таймер */
NVIC_EnableIRQ(TIM3_IRQn); /* Разрешаем прерывания таймера TIM3 */
}
void TIM3_IRQHandler(){
uint16_t enc1, enc2;
if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET) {
TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
do {
enc1 = ReadEncoder();
enc2 = ReadEncoder();
} while (enc1!=enc2);
// здесь используем правильное значение enc1.
if(State == 0){
State = 1;
pos = enc1;
}
GPIOA->ODR ^= GPIO_Pin_1;
}
}

uint16_t ReadEncoder()
{
uint16_t PA, PB;
PA = ~GPIOA->IDR;
PB = ~GPIOB->IDR;
return 0
| (PA & 0b0000000000100000) >> (6 - 0)
| (PA & 0b0000010000000000) >> (11 - 1)
| (PA & 0b0000001000000000) >> (10 - 2)
| (PA & 0b0000000100000000) >> (9 - 3)
| (PA & 0b0000000010000000) >> (8 - 4)
| (PB & 0b1000000000000000) >> (15 - 5)
| (PB & 0b0100000000000000) >> (14 - 6)
| (PB & 0b0010000000000000) >> (13 - 7)
| (PB & 0b0001000000000000) >> (12 - 8)
| (PB & 0b0000100000000000) >> (11 - 9);
}


Сообщение отредактировал Alexsandr000 - Oct 22 2014, 08:14


--------------------
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Oct 22 2014, 08:35
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



что за бред?
если у вас на столе сбоит, на объекте будет полный пи....

Не та задача чтобы ее нельзя было решить без сбоя.

Уверены что сбоит не UART а энкодер? Если уарт добавьте проверку целостности, обвешайте протоколом. Если энкодер, то предложенный вариант считывания от АНТОХА (не знаю можно ли склонятьsm.gif) должен гарантированно отдавать правильное установившееся значение...
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Closed TopicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 01:18
Рейтинг@Mail.ru


Страница сгенерированна за 0.0153 секунд с 7
ELECTRONIX ©2004-2016