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

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Дополнение для радиоаппаратуры 2.4GHz
e-leks
сообщение Mar 25 2012, 15:42
Сообщение #1


Участник
*

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



Добрый день.

Разрабатываю дополнение для радиоаппаратуры. Вот кое-что написал прошу Ваших комментариев, по алгоритму, организации кода, что можно улучшить.
Код
/**
Задача:
Необходимо управлять коллекторным двигателем по средствам ШИМ.
Двигатель должен начинать движение с ускорением.
Управление должно происходить в зависимости от входных сигналов.
Входы:
1. Основной сигнал - прямоугольные импульсы амплитудой 5В, длительностью 20 мС,
вехняя часть 1000 - 2000 мкС.
2. Два дискретных датчика - верхнее и нижнее положение.
Выходы:
Два выхода процессора, их комбинации управляют двигателем.
Вверх - по ч.с., вниз против ч.с.
    |--------------------------------------------------------|
    |            |Стоит  |Вверх  |Вниз   |Зафиксирован   |
    |--------------------------------------------------------|
    |Выход1 |    0         1         0           1                   |
    |--------------------------------------------------------|
    |Выход2 |    0         0         1           1                   |
    |--------------------------------------------------------|
*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "AE_Util.h"

#define PULSE_PIN           PIND
#define PULSE_PPIN          PD2
#define PULSE_MID_WIDTH     188// Средняя длительность импульса 1500/8 = 188.
#define PULSE_WIDTH_TOLER   5 // Допуск по ширине импульса
#define PULSE_QUANTITY      10 // Количество анализируемых импульсов (0...255)

#define MOT_DDR             DDRD
#define MOT_PORT            PORTD
#define MOT_PIN1            PD4
#define MOT_PIN2            PD5
#define MOT_UP              sbi(MOT_PORT, MOT_PIN1); cbi(MOT_PORT, MOT_PIN2)
#define MOT_DOWN            cbi(MOT_PORT, MOT_PIN1); sbi(MOT_PORT, MOT_PIN2)
#define MOT_STANDBY         cbi(MOT_PORT, MOT_PIN1); cbi(MOT_PORT, MOT_PIN2)

#define SEN_PIN             PINA
#define SEN_UP_PIN          PA0
#define SEN_DOWN_PIN        PA1

enum {S_NO, S_UP, S_DOWN, S_BOTH};

// Глобальные переменные
volatile u8 g_abPUW[PULSE_QUANTITY];// Массив ширин верхней части импульса 1 == 8 мкС.
volatile u8 g_bPulNum;

// Глобальные функции
u8 Measuring();
u8 GetSen();

ISR(INT0_vect)
{
    if(PULSE_PIN & (1 << PULSE_PPIN)) // Начало верхней части
    {
        TCCR0=0x03;
        TCNT0=0x00;
    }
    else // Конец верхней части
    {
        if(TCCR0 != 0)// Только если таймер предварительно был запущен, чтобы замеры делать с начала импульса
        {
            g_abPUW[g_bPulNum++] = TCNT0;
            TCCR0=0x00;
        }

    }
}

int main(void)
{
    sbi(MOT_DDR, MOT_PIN1);
    sbi(MOT_DDR, MOT_PIN2);

    // Чтобы входные импульсы стабилизировались
    _delay_ms(500);
    while(1)
    {
        if(GetSen() != S_DOWN)
        {
            MOT_DOWN;
            while(GetSen() != S_DOWN);
            MOT_STANDBY;
        }
        else
        {
            u8 bTol, bMid;
            do
            {
                bMid = Measuring();
                if(bMid <= PULSE_MID_WIDTH)
                {
                    bTol = PULSE_MID_WIDTH - bMid;
                }
                else
                {
                    bTol = bMid - PULSE_MID_WIDTH;
                }
            }while(bTol < PULSE_WIDTH_TOLER);
            MOT_UP;
            while(GetSen() != S_UP);
            MOT_STANDBY;
            _delay_ms(500);
            MOT_DOWN;
            while(GetSen() != S_DOWN);
            MOT_STANDBY;
        }
    }

    return 0;
}

u8 Measuring()
{
    g_bPulNum = 0;
    TCCR0=0x00;// Таймер выключен
    sbi(GICR, INT0);// Разрешаем прерывание INT0
    cbi(MCUCR, ISC01);// Прерывание будет происходить при любом изменении уровня на INT0
    sbi(MCUCR, ISC00);
    sbi(GIFR, INTF0);// Сбросить прерывание INT0
    sei();// Глобальное разрешение прерываний

    while(g_bPulNum < PULSE_QUANTITY);// Ожидаем необходимое количество импульсов

    cli();
    cbi(GICR, INT0);
    TCCR0 = 0x00;

    // Вычисляем среднее значение
    u8 b;
    int iMid = 0;
    for(b = 0; b < PULSE_QUANTITY; b++)
    {
        iMid += g_abPUW[b];
    }
    iMid /= PULSE_QUANTITY;

    return iMid;
}

u8 GetSen()
{
    volatile u8 bRes = SEN_PIN & (1 << SEN_DOWN_PIN);
    bRes |= (SEN_PIN & (1 << SEN_UP_PIN));
    return bRes;
}
Go to the top of the page
 
+Quote Post
kovigor
сообщение Mar 25 2012, 17:34
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 5 273
Регистрация: 30-03-10
Пользователь №: 56 295



Цитата(e-leks @ Mar 25 2012, 19:42) *
Разрабатываю дополнение для радиоаппаратуры. Вот кое-что написал прошу Ваших комментариев, по алгоритму, организации кода, что можно улучшить.
Задача:
Необходимо управлять коллекторным двигателем по средствам ШИМ.
Двигатель должен начинать движение с ускорением.


А что, можно начать движение и без ускорения ??? Интересно, и очень.
А по делу - невозможно понять, какой совет вам нужен. Изучать чужой код у меня нет ни малейшего желания, особенно после прочтения первых комментариев, содержащих массу самых разных ошибок ...
Go to the top of the page
 
+Quote Post
e-leks
сообщение Mar 25 2012, 18:22
Сообщение #3


Участник
*

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



Цитата(kovigor @ Mar 25 2012, 21:34) *
...комментариев, содержащих массу самых разных ошибок ...
Можно было указать хотя бы каких? Вообще не ожидал такого качества помощи в ветке "для начинающих". Еще раз спасибо!

Сообщение отредактировал e-leks - Mar 25 2012, 18:22
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Mar 25 2012, 21:26
Сообщение #4


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

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



Ошибка вроде всего одна: "по средствам ШИМ". Надо: "посредством ШИМ". Сам код понравился, очень аккуратно, все константы поименованы. Если он работает, то вообще прекрасно. Замечание придумалось только одно - в функции GetSen() локальной переменой bRes не обязательно иметь квалификатор volatile, поскольку сам порт (SEN_PIN) является volatile.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Mar 26 2012, 11:26
Сообщение #5


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658



Цитата(e-leks @ Mar 25 2012, 18:42) *
Вот кое-что написал прошу Ваших комментариев, по алгоритму, организации кода, что можно улучшить.

Насчет алгоритма , думаю былобы намного нагляднее еслибы вы нарисовали алг. ввиде блочной схемы , а программа как ее реализация.
Кстати, интересно что у вас в "AE_Util.h" ?
Go to the top of the page
 
+Quote Post
e-leks
сообщение Mar 26 2012, 16:24
Сообщение #6


Участник
*

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



Постараюсь конкретизировать вопросы.
1. С/С++ является аппаратно-независимый языком. Т.е. в основном коде программы не должно быть записей типа "PORTB"?
Код
#define MOTOR_PORT PORTA
volatile uint8_t *pMotorPotr = &PORTB;
Какой вариант более предпочтителен?
Хотелось бы знать как специалисты соединяют аппарат с программой. Правильно ли я понимаю что в основном это делается чтобы при необходимости поменять камень?
Как нибудь так.
Код
#ifdef KAMEN1
#define MOTOR_PORT PORTA
#elif defined KAMEN2
#define MOTOR_PORT PORTB
#endif

Для AHTOXA: Большое спасибо! Очень трудно разбириться в вопросе без поддержки.
Для MaxiMuz: Файл AE_Util.h:
Код
#ifndef AE_UTIL_H
#define AE_UTIL_H

#define cbi(reg, bit) (reg &= ~(1<<bit))
#define sbi(reg, bit) (reg |= (1<<bit))
#define u8 unsigned char

#endif // AE_UTIL_H

Здесь мои мизерные утилиты.
А алгоритм такой:
1. Измеряем ширину верхних частей определенного кол-ва импульсов.
2. Находим среднее значение.
3. В зависимости от результата, управляем двигателем или не трогаем его.
4. Вообще должен получится самосвал. Если средняя ширина импульса отличается от заданной (кто-то дернул рычаг на передатчике), подаем кузов вверх.
5. Ждем пока отчитается датчик верхнего положения.
6. Пауза.
7. Переполюсовываем движек.
8. Дожидаемся отчета датчика нижнего положения.
И опять пункт №1.

Сообщение отредактировал e-leks - Mar 26 2012, 16:27
Go to the top of the page
 
+Quote Post
kovigor
сообщение Mar 26 2012, 17:59
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 5 273
Регистрация: 30-03-10
Пользователь №: 56 295



Цитата(e-leks @ Mar 26 2012, 19:24) *
А алгоритм такой:
1. Измеряем ширину верхних частей определенного кол-ва импульсов.
2. Находим среднее значение.
3. В зависимости от результата, управляем двигателем или не трогаем его.
4. Вообще должен получится самосвал. Если средняя ширина импульса отличается от заданной (кто-то дернул рычаг на передатчике), подаем кузов вверх.
5. Ждем пока отчитается датчик верхнего положения.
6. Пауза.
7. Переполюсовываем движек.
8. Дожидаемся отчета датчика нижнего положения.
И опять пункт №1.


Не знаю, может, я чего-то не понял, но алгоритм тут проще простого - берем отсчеты с линии, на которой вы наблюдаете ваш ШИМ - сигнал (достаточно часто берем), например, в течение секунды. Получаем либо нули, либо единички. Единички приплюсовываем друг к другу в какой-то переменной, нули отбрасываем. Спустя секунду смотрим, сколько принято единичек. Если больше некоторого порога - что-то там включаем или выключаем.

P.S. Еще раз. Все ваши сообщения составлены так, что из них крайне трудно что-то понять. Проще говоря, они составлены небрежно. Обижайтесь - не обижайтесь, но это так. Учитесь кратко и четко формулировать свои мысли ...
Go to the top of the page
 
+Quote Post
e-leks
сообщение Mar 26 2012, 18:23
Сообщение #8


Участник
*

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



Цитата(kovigor @ Mar 26 2012, 21:59) *
...в течение секунды. Получаем либо нули, либо единички. Единички приплюсовываем друг к другу в какой-то переменной, нули отбрасываем. Спустя секунду смотрим, сколько принято единичек. Если больше некоторого порога - что-то там включаем или выключаем...

У сигнала ШИМ частота постоянна, это Вам не ЧИМ, соответственно количество единичек за определенный промежуток времени будет одинаково.
Алгоритм измерения:
1. В начале верхней части импульса обнуляем регистр таймера и запускаем его.
2. В конце верхней части сохраняем результат регистра таймера в массив и при желании останавливаем таймер и обнуляем регистр.
3. Повторяем предыдущие пункты необходимое количество раз.
4. Берем элементы массива и высчитываем среднее значение.
Цитата(kovigor @ Mar 26 2012, 21:59) *
...Все ваши сообщения составлены так, что из них крайне трудно что-то понять...

Мне далеко до Вас в плане электронники, поэтому я обращаюсь к Вам. Подскажите как правильно задавать вопросы.
Мой вопрос
Цитата
Хотелось бы знать как специалисты соединяют аппарат с программой?
достаточно конкретен?
Go to the top of the page
 
+Quote Post
kovigor
сообщение Mar 26 2012, 18:33
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 5 273
Регистрация: 30-03-10
Пользователь №: 56 295



Цитата(e-leks @ Mar 26 2012, 21:23) *
У сигнала ШИМ частота постоянна, это Вам не ЧИМ, соответственно количество единичек за определенный промежуток времени будет одинаково.


Почему это ????? Частота постоянна, это так. Например, 1 КГц. Допустим, у нас есть два сигнала. Первый сигнал - 1000 миллисекундных иголочек, принятых за секунду. Второй сигнал - 1000 200-миллисекундных импульсов, принятых, опять же, за секунду. Применяем к этим наборам импульсов мой алгоритм. Как думаете, для какого из наборов мы получим больше единичек ? И во сколько раз больше мы их получим ?
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Mar 26 2012, 18:34
Сообщение #10


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

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



Цитата(e-leks @ Mar 26 2012, 22:24) *
1. С/С++ является аппаратно-независимый языком. Т.е. в основном коде программы не должно быть записей типа "PORTB"?

Если программа работает с портом, то ей никак не обойтись без записей типа "PORTB" sm.gif

Если планируете применять разные камни, то можете сделать что-то типа файла-описания аппаратной платформы. Например, в файле camen1.h:
Код
#define MOTOR_UP что-то_там
#define MOTOR_DOWN что-то_там
, в файле camen2.h то же самое, но для камня-2. И в зависимости от камня, для которого собираете, включайте нужный заголовочный файл. Если замените #define на inline-функции, то это будет ещё красивее. Это уже получится мини-HAL, hardware-abstraction layer (уровень абстрагирования от аппаратуры).

ЗЫ. "В начале верхней части импульса" = "по фронту", "в конце верхней части" = "по спаду". Так понятнее.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Mar 27 2012, 11:45
Сообщение #11


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658



Судя по описанию и самой программе , управление скоростью двигателя не предусмотренно.
Цитата
Необходимо управлять коллекторным двигателем по средствам ШИМ.
Двигатель должен начинать движение с ускорением.
Управление должно происходить в зависимости от входных сигналов.
по ШИМ только задается вх.воздействие , кот. запускает процесс

а к чему "Дополнение для радиоаппаратуры 2.4GHz" вообще непонятно )
Go to the top of the page
 
+Quote Post
kovigor
сообщение Mar 27 2012, 13:03
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 5 273
Регистрация: 30-03-10
Пользователь №: 56 295



Цитата(MaxiMuz @ Mar 27 2012, 14:45) *
а к чему "Дополнение для радиоаппаратуры 2.4GHz" вообще непонятно )


Я понял, но только через примерно сутки после прочтения темы. Автор темы - моделист, и он хочет добавить к своей аппаратуре радиоуправления новую функцию.
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Mar 27 2012, 15:31
Сообщение #13


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658



e-leks не указал каким компилятором пользуется, но кстати у меня подобная конструкция
Код
while(GetSen() != S_DOWN);
в WinAVR с -Оs ключом не работает!
Go to the top of the page
 
+Quote Post
e-leks
сообщение Mar 27 2012, 16:55
Сообщение #14


Участник
*

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



Цитата(kovigor @ Mar 26 2012, 22:33) *
Допустим, у нас есть два сигнала.
Нет же сигнал один, частота 50Гц, ширина верхней части варьируется в зависимости от команды от приемника. Соответственно ваш метод даст 50 единичек вне зависимости от команд (ширины импульса).

Цитата(AHTOXA @ Mar 26 2012, 22:34) *
Если программа работает с портом, то ей никак не обойтись без записей типа "PORTB" sm.gif
Если возможно приведите пример Вашего кода касаюшийся обращения к порту. В теле main() запись типа PORTA выглядит как то по-детски? Нет?

Цитата(AHTOXA @ Mar 26 2012, 22:34) *
Если замените #define на inline-функции, то это будет ещё красивее. Это уже получится мини-HAL...
Можно микропример?

Цитата(MaxiMuz @ Mar 27 2012, 15:45) *
Судя по описанию и самой программе , управление скоростью двигателя не предусмотренно.
по ШИМ только задается вх.воздействие , кот. запускает процесс

а к чему "Дополнение для радиоаппаратуры 2.4GHz" вообще непонятно )
Да к сожалению скорость не регулируется, просто пока не подобрал драйвер (аппаратный) для двигателя. А дополнение в следующем. Есть стандартная аппаратура приемник-передатчик управляет моделями в связке с сервомашинками. Приемник имеет несколько каналов с сигналом ШИМ, для сервомашинок это и нужно. Мне понадобилось приделать к модели что-то типа самосвала. Двигатель через пасик вращает ось, по оси ходит ползун. Ползун через шарнир прикреплен к одной стороне кузова. Также на ползуне две пружинки (датчики верхнего и нижнего положения). Все...

Цитата(MaxiMuz @ Mar 27 2012, 19:31) *
e-leks не указал каким компилятором пользуется, но кстати у меня подобная конструкция
Код
while(GetSen() != S_DOWN);
в WinAVR с -Оs ключом не работает!
Компилятор GNU AVR GCC, среда Code::Blocks 10.05. Лично у меня все компилируется без ошибок, даже в Proteus все работает.
Уважаемые участники, если это не затрагивает Ваших религиозных убеждений, приведите участки Вашего "реального" кода где вы из main() обращаетесь к портам и регистрам.
Удачи.

Сообщение отредактировал e-leks - Mar 27 2012, 17:32
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Mar 27 2012, 18:27
Сообщение #15


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658



По поводу
Код
while(GetSen() != S_DOWN);
может быть не совсем то что у вас, покажу на примере:
Код
    while(flag_ms != 2);
  32:    80 91 60 00     lds    r24, 0x0060
  36:    82 30           cpi    r24, 0x02; 2
  38:    19 f4           brne    .+6      ; 0x40 <__SREG__+0x1>
    TCNT0=10;
  3a:    8a e0           ldi    r24, 0x0A; 10
  3c:    82 bf           out    0x32, r24; 50
  3e:    08 95           ret
  40:    ff cf           rjmp    .-2      ; 0x40 <__SREG__+0x1>
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 21st July 2025 - 17:02
Рейтинг@Mail.ru


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