Проект с использованием MCC часть 16

Просмотров: 896


Продолжим изучение EUSART. На этом этапе отработает передачи данных с ПК и получения эха.

Для этого в основной цикл программы добавим код

        if(EUSART_DataReady) // проверим флаг готовности данных в буфере
        {
            data = EUSART_Read();		// прочитать данные
            EUSART_Write(data);			// вернуть в ПК это
        }

Суть его проста постоянно в главном цикле проверяется наличие данных в буфере (размер нашего буфера не забываем 8 байт). Если флаг установлен сосчитать байт из буфера EUSART_Read() и вернуть его в ПК. Протестируем:

После компиляции и прошивки микроконтроллера, в окне передачи данных введем надпись “Привет!” и нажмем кнопку Send. В окне приемника прочитаем наше сообщение.

Добавим в конце строки “Привет!” код перевод строки, для этого просто нажмем клавишу Энтер. Поставим птичку Period значение по умолчанию 1 секунда и нажмем клавишу Send. Программа будет автоматически с периодом будет передавать, а наш контроллер возвращать сообщение с эхом.

В общем так просто наладить двухсторонний обмен данными с ПК.


Теперь перейдем к сути нашего проекта.

Для начала добавим сообщения о состоянии регулятора, которые будут передаваться в ПК, при изменении режима работы. Первое, что сделаем, для удобства понимания логики работы программы, создадим функцию индикации и формирования сообщений для ПК. И перенесем все строки с этим связанные из главного цикла, при этом главный цикл на текущем этапе будет выглядеть так:

    while (1)
    {

        // формирование эха для уарт
        if(EUSART_DataReady) // проверим флаг готовности данных в буфере
        {
            data = EUSART_Read();		// прочитать данные с буфера
            EUSART_Write(data);			// вернуть в ПК это
        }
        
        CLRWDT();   //сброс сторожевого таймера +++++++++++++++++++++-    
        channel_1 (); // управление каналом 1
        channel_2 (); // управление каналом 1

        // индикация и сообщения
        mes_ind ();
        
    }

После этого намного упрощается понимание принципа работы.

После этого добавим в нашу строки для вывода сообщений о состоянии регулятора. Еще раз опишем проблему с которой придется столкнуться, при изменении режима, должно быть сформировано одно сообщение и оно должно быть передано в ПК, сообщение должно передаваться с учетом того, что у нас буфер маленький всего 8 байт и если мы будем его грузить быстрее чем будет идти передача, то на выходите получим фигню. С этим бороться можно несколькими способами, но самым простом может быть просто увеличить скорость передачи, что бы УАРТ отправлял данные по быстрее или увеличить размер самого буфера или формировать сообщения не превышающие размер буфера или разбивать сообщения и делать паузы при передачи. Но на текущем этапе у нас все ок, самое главное понимать, с чем бороться. Вторая проблема, это то для формирования одного сообщения, как для дисплея так и для УАРТа надо добавить флаги состояния, при изменении состояния программа будет сравнивать текущее состояния с предыдущим и если они не будут совпадать формировать сообщения. Например для индикации состояния канала 1 будет иметь следующий вид:

    if(IND01P != PWM1EN)    // когда два канала отключены. очистить дисплей и прорисовать линию
    {
        IND01P = PWM1EN;    // запомнить состояние
        if(PWM1EN)printf("\t\tКанал 1 - включен\n\r");
        else printf("\t\tКанал 1 - выключен\n\r");
    }

Сама функция будет иметь вид:

// индикация и сообщения
void mes_ind (void)
{
    if(IND01P != PWM1EN)    // когда два канала отключены. очистить дисплей и прорисовать линию
    {
        IND01P = PWM1EN;    // запомнить состояние
        if(PWM1EN)printf("\t\tКанал 1 - включен\n\r");
        else printf("\t\tКанал 1 - выключен\n\r");
    }
    if(IND02P != PWM2EN)    // когда два канала отключены. очистить дисплей и прорисовать линию
    {
        IND02P = PWM2EN;    // запомнить состояние
        if(PWM2EN)printf("\t\tКанал 2 - включен\n\r");
        else printf("\t\tКанал 2 - выключен\n\r");
    }

    if(!ECONOM && !PWM1EN && !PWM2EN) // когда два канала отключены. очистить дисплей и прорисовать линию
    {
        ECONOM = 1;
        OLED_clear (0);
        OLED_String ("------", 0, 1, 1, -1, 3);
        printf("\t\tВсе каналы отключены\n\n\r");
    }
    else if(PWM1EN || PWM2EN) // выход из эконом режима
    {
        // выполнить функцию один раз
        if(ECONOM) // когда любой канал включен
        {
            ECONOM = 0;
            OLED_clear (0);
            OLED_String ("Освещение", 0, 1, 1, -1, 7);
            OLED_String ("Прихожая", 0, 1, 1, 1, 4);
            OLED_String ("Коридор", 0, 1, 1, 1, 1);
            // для первого включения
            PWM1_LoadDutyValue(brightness_chn1);
            PWM2_LoadDutyValue(brightness_chn2);
            // для прорисовки значений 
            pro_bri1p=200;
            pro_bri2p=200;
            SHIM1=0;
            SHIM2=0;
            NAP1 = 1;
            NAP2 = 1;
        }

        // индикация для канала 1
        if(!PWM1EN && !SHIM1)
        {
            SHIM1=1;  //
            OLED_String ("откл", 0, 2, 2, 60, 4);
            OLED_Symbol (' ',0,0,1,1);
            OLED_Symbol (' ',0,0,1,1);
            pro_bri1p=200;
        }
        else if(PWM1EN && (pro_bri1 != pro_bri1p))
        {
            pro_bri1p=pro_bri1;  // сбросить несоответствие
            SHIM1=0;
            OLED_curcor(60,4);
            OLED_BinDec(pro_bri1, 0, 0, 4, 1, 2, 2);
            OLED_Symbol (' ',0,0,1,1);
            OLED_Symbol ('%',0,0,1,1);
            if(!pro_bri1)
            {
                __delay_ms (500);   // показать, что значение установленной яркости 0
                OLED_String ("откл", 0, 2, 2, 60, 4);
                pro_bri1p=200;  // инициализировать яркость для возможности следующей индикации
                PWM1EN=0;       // отключить шим
                SHIM1=1;        // установить флаг
                NAP1 = 1;       // изменить направление 
                __delay_ms (500); // показать что регулятор отключен
            }
        }
        else if(AUTO_OFF1 && (timer_OFF1 != timer_OFF1p))
        {
            timer_OFF1p=timer_OFF1;// сбросить несоответствие
            OLED_curcor(60,4);
            OLED_BinDec(timer_OFF1/2, 0, 0, 4, 1, 2, 2);
            OLED_Symbol (' ',0,0,1,1);
            OLED_Symbol ('C',0,0,1,1);
        }

        // индикация для канала 2
        if(!PWM2EN && !SHIM2)
        {
            SHIM2=1;  //
            OLED_String ("откл", 0, 2, 2, 60, 1);
            OLED_Symbol (' ',0,0,1,1);
            OLED_Symbol (' ',0,0,1,1);
            pro_bri2p=200;
        }
        else if(PWM2EN && pro_bri2!=pro_bri2p)
        {
            pro_bri2p=pro_bri2;  // сбросить несоответствие
            SHIM2=0;
            OLED_curcor(60,1);
            OLED_BinDec(pro_bri2, 0, 0, 4, 1, 2, 2);
            OLED_Symbol (' ',0,0,1,1);
            OLED_Symbol ('%',0,0,1,1);
            if(!pro_bri2)
            {
                __delay_ms (500);   // показать, что значение установленной яркости 0
                OLED_String ("откл", 0, 2, 2, 60, 1);
                pro_bri2p=200;  // инициализировать яркость для возможности следующей индикации
                PWM2EN=0;       // отключить шим
                SHIM2=1;        // установить флаг
                NAP2 = 1;       // изменить направление 
                __delay_ms (500); // показать что регулятор отключен
            }
        }
        else if(AUTO_OFF2 && (timer_OFF2 != timer_OFF2p))
        {
            timer_OFF2p=timer_OFF2;// сбросить несоответствие
            OLED_curcor(60,1);
            OLED_BinDec(timer_OFF2/2, 0, 0, 4, 1, 2, 2);
            OLED_Symbol (' ',0,0,1,1);
            OLED_Symbol ('C',0,0,1,1);
        }
    } 
}

Проект для промежуточного тестирования и работа самой программы

Значок

Проект с использованием MCC часть 16 (1) 828.68 KB 305 downloads

Изучаем УАРТ - формирование сообщений   ...


Следующий этап это придумать команды управления. Какие команды нам могут понадобиться:

  • включить/выключить канал
  • задать освещенность
  • включить таймер
  • получить значение яркости канала.

В общем все то, что мы делаем с кнопок управления.

Для команд желательно выбрать фиксированный формат, чтобы все обрабатывать под “одну гребенку”. Если мы мы будем формировать команды при помощи стандартных символьных строк, то нам потребуется прибегнуть к библиотеки обработки строк (или делать её самому, что будет утомительно) или формировать в качестве байтовых команд. В каждом есть свои плюсы и минусы, но для наглядности остановимся на передачи команд при помощи строк (но это хорошо, для обучения, а даже для домашней автоматики такой принцип будет не приемлем).

Для команд управления отведем 5 символов

1-вкл – первый канал включить

1-отк – первый канал выключить

1-050 – первый канал на 50% яркости

1-100 – первый канал на 100% яркости

1-тай – таймер включить

1-сос – сообщить состояние яркости 1 канала

Для начала определим принцип как мы будем обрабатывать получаемые данные (надо еще понимать, что все происходит, по элементарным правилам, у нас “в сети” УАРТ перемещаются фиксированные пакеты и мы считаем, что условия идеальные и нет помех). Мы ждем когда будут принято 5 байт в буфер и произведем его чтение. После этого мы знаем, что 0 байт в буфере это адрес канала, для этого мы должны проверить какой символ в нулевом байте и после этого принимать решение что делать дальше, для теста сделаем следующую функцию (прямо в главный цикл):

        if(EUSART_DataReady>=5) // проверим флаг готовности данных в буфере
        {
            for(a=0;a<5;a++)
            {
                data[a] = EUSART_Read();		// прочитать данные с буфера
            }
            
            if(data[0]=='1') // определение канала управления
            {
                EUSART_Write('6');			// вернуть в ПК это
            }
            
            else if(data[0]=='2') // определение канала управления
            {
                EUSART_Write('5');			// вернуть в ПК это
            }
//            
        }

Мы тестируем например, командами яркости 1-100 и 2-100, при этом нам регулятор должен ответить 1-100 – вернуть символ 6, на 2-100 вернуть символ 5 (правда тут важен только первый символ в команде, что будут потом не важно). Тестирование функции:

 Функция работает, теперь перейдем к созданию первых управляющих команд. Самое сложное это подстроиться под функции которые предлагает МСС. Естественно, что намного проще сделать свой и они будут более эффективны, но попробуем использовать данные нам в действительности.

Чтение буфера будем выполнять следующим образом:

        if(EUSART_DataReady) // проверим флаг готовности данных в буфере
        {
            data[count_bayt] = EUSART_Read();		// прочитать данные с буфера
            count_bayt++;       // счетчик принятых байт
        }

Смысл такой если флаг установлен считываем один раз буфер и увеличиваем счетчик принятых байт. Далее будет идти программа анализа принятых байт. Анализ должен начинаться при условии когда количество принятых байт равен или более 5. Первое надо проанализировать байт 0 – чтобы определиться к какому регулятору относиться команда, а далее читаем второй байт и выполняем команду.

        if(count_bayt>=5)
        {
            if(data[0]=='1') // определение канала управления
            {
                if(data[2]=='в')
                {
                    PWM1EN=1;
                    printf("\t\tКоманда включения канала 1\n\r");
                    __delay_ms(2);
                }
                else if(data[2]=='о')
                {
                    PWM1EN=0;
                    printf("\t\tКоманда выключения канала 1\n\r");
                    __delay_ms(2);
                }
            }
            else if(data[0]=='2') // определение канала управления
            {
                if(data[2]=='в')
                {
                    PWM2EN=1;
                    printf("\t\tКоманда включения канала 2\n\r");
                    __delay_ms(2);
                }
                else if(data[2]=='о')
                {
                    PWM2EN=0;
                    printf("\t\tКоманда выключения канала 2\n\r");
                    __delay_ms(2);
                }
            }
            // инициализация приемного буфера
            for(a=0;a<8;a++)if(EUSART_DataReady)EUSART_Read();  
            count_bayt=0;
        }

Из текста программы, видно как выполняется логика анализа команд включения выключения каналов. Но главное, что бы корректно использовать буфер обмен, чтобы он правильно инициализировался после приема команд “нестандартной” длины мы добавили строки, суть их может понять если проанализировать прием байт в функции EUSART_Receive_ISR. После получения данных нам необходимо инициализировать приемный буфер, для того, что следующие полученные данные начали загружаться опять с начала буфера, т.е после приема 5 байт выполняется синхронизация приемного буфера:

            // инициализация приемного буфера
            for(a=0;a<8;a++)if(EUSART_DataReady)EUSART_Read();  
            count_bayt=0;

Результаты тестирования:

Проект для промежуточного тестирования

Значок

Проект с использованием MCC часть 16 (2) 833.68 KB 281 downloads

Управление приемным буфером, тестирование команд...

Добавим команды управления таймером (обратите внимание, что все символы в кириллице и вся кодировка проекта  в W1251!!!).

                ...
                else if(data[2]=='т')
                {
                    if(PWM1EN && !AUTO_OFF1) // если модуль включен (свет горит)
                    {
                        AUTO_OFF1=1; // установить флаг автоотключение канала 1
                        timer_OFF1=TIMEOFF*2; // *2 так как отсчет идет в два раза быстрее, по 0,5 секунды
                        printf("\t\tВключен таймер канала 1\n\r");
                    }
                    else if(!PWM1EN) printf("\t\tКанала 1 - отключен\n\r");
                }
                ...

Если определено, что получено команда “таймер”, мы проверяем, что канал включен PWM1EN == 1 и таймер не активен AUTO_OFF1 == 0. Запускаем таймер и отправляем сообщение в УАРТ, если канал отключен, сообщаем, что отключение через таймер бесполезно, канал отключен.

Для управления яркость добавим следующее условие обработки данных, если во втором байте у нас число, значит это данные яркости, преобразуем из в число, это есть проценты (допустимое значение 0-100). Потом преобразуем в значение ШИМ, контролируем. чтобы оно не превышало максимальное значение 1023. Затем грузим данные модуль ШИМ и корректируем данные индикации.

                else if(data[2]>='0' && data[2]<='9')
                {
                    brightness_chn1= (data[2]-0x30)*100;
                    brightness_chn1+=(data[3]-0x30)*10;
                    brightness_chn1+=(data[4]-0x30);
                    
                    brightness_chn1=(uint16_t)((long)brightness_chn1*1023/100+1);
                    if(brightness_chn1>1023)brightness_chn1=1023;
                    PWM1_LoadDutyValue(brightness_chn1); 
                    printf("\t\tКанала 1 - изменена яркость\n\r");
                    pro_bri1=(uint8_t)((long)brightness_chn1*100/1023);
                }

Тестируем работу:

 Для красоты выделим это все в функцию дистанционного управления remote ().

void remote (void) // дистанционное управление
{
    if(EUSART_DataReady) // проверим флаг готовности данных в буфере
    {
        data[count_bayt] = EUSART_Read();		// прочитать данные с буфера
        count_bayt++;       // счетчик принятых байт
    }

    if(count_bayt>=5)
    {
        if(data[0]=='1') // определение канала управления
        {
            if(data[2]=='в')
            {
                AUTO_OFF1=0;    // отключить таймер
                PWM1EN=1;
                printf("\t\tКоманда включения канала 1\n\r");
                __delay_ms(2);
            }
            else if(data[2]=='о')
            {
                AUTO_OFF1=0;    // отключить таймер
                PWM1EN=0;
                printf("\t\tКоманда выключения канала 1\n\r");
                __delay_ms(2);
            }
            else if(data[2]=='т')
            {
                if(PWM1EN && !AUTO_OFF1) // если модуль включен (свет горит)
                {
                    AUTO_OFF1=1; // установить флаг автоотключение канала 1
                    timer_OFF1=TIMEOFF*2; // *2 так как отсчет идет в два раза быстерее, по 0,5 секунды
                    printf("\t\tВключен таймер канала 1\n\r");
                }
                else if(!PWM1EN) printf("\t\tКанала 1 - отключен\n\r");
            }
            else if(data[2]>='0' && data[2]<='9')
            {
                brightness_chn1= (data[2]-0x30)*100;
                brightness_chn1+=(data[3]-0x30)*10;
                brightness_chn1+=(data[4]-0x30);

                brightness_chn1=(uint16_t)((long)brightness_chn1*1023/100+1);
                if(brightness_chn1>1023)brightness_chn1=1023;
                PWM1_LoadDutyValue(brightness_chn1); 
                printf("\t\tКанала 1 - изменена яркость\n\r");
                pro_bri1=(uint8_t)((long)brightness_chn1*100/1023);
            }
        }
        else if(data[0]=='2') // определение канала управления
        {
            if(data[2]=='в')
            {
                AUTO_OFF2=0;    // отключить таймер
                PWM2EN=1;
                printf("\t\tКоманда включения канала 2\n\r");
                __delay_ms(2);
            }
            else if(data[2]=='о')
            {
                AUTO_OFF2=0;    // отключить таймер
                PWM2EN=0;
                printf("\t\tКоманда выключения канала 2\n\r");
                __delay_ms(2);
            }
            else if(data[2]=='т')
            {
                if(PWM2EN && !AUTO_OFF2) // если модуль включен (свет горит)
                {
                    AUTO_OFF2=1; // установить флаг автоотключение канала 1
                    timer_OFF2=TIMEOFF*2; // *2 так как отсчет идет в два раза быстрее, по 0,5 секунды
                    printf("\t\tВключен таймер канала 2\n\r");
                }
                else if(!PWM2EN) printf("\t\tКанала 2 - отключен\n\r");
            }
            else if(data[2]>='0' && data[2]<='9')
            {
                brightness_chn2= (data[2]-0x30)*100;
                brightness_chn2+=(data[3]-0x30)*10;
                brightness_chn2+=(data[4]-0x30);

                brightness_chn2=(uint16_t)((long)brightness_chn2*1023/100+1);
                if(brightness_chn2>1023)brightness_chn2=1023;
                PWM2_LoadDutyValue(brightness_chn2); 
                printf("\t\tКанала 2 - изменена яркость\n\r");
                pro_bri2=(uint8_t)((long)brightness_chn2*100/1023);
            }
        }
        // инициализация приемного буфера
        for(a=0;a<8;a++)if(EUSART_DataReady)EUSART_Read();  
        count_bayt=0;
    }
}  

Проект для тестирования

Значок

Проект с использованием MCC часть 16 (3) 849.44 KB 86 downloads

Полнофункциональный проект двухканального...


Естественно можно и дальше наворачивать функции, например добавить часы реального времени, но я считаю нудно перейти к исследованию новых периферийных модулей таких как:



Это может быть интересно


  • MCC – K42 – настройка модуля DMAMCC – K42 – настройка модуля DMA
    Просмотров: 636 MCC – в версии v.3.95.0 и начиная ядра 4.85.0 конфигуратор предоставляет графический интерфейс для настройки модуля DMA. Для начала: Посмотреть какая версия МСС можно в закладке версии, если …
  • NeoPixel LED and PIC24NeoPixel LED and PIC24
    Просмотров: 419 Популярность однопроводной шины для управления светодиода типа WS2812 не ослабевает, а новые типы светодиодов в корпусах 3,5*3,5мм, 2,0*2,0мм становяться все больше привлекательными. Построение дисплеев для анимации требуют все …
  • LM317 и светодиодыLM317 и светодиоды
    Просмотров: 7442 LM317 и светодиоды статья с переработанная с сайта http://invent-systems.narod.ru/LM317.htm Долговечность светодиодов определяется качеством изготовления кристалла, а для белых светодиодов еще и качеством люминофора. В процессе эксплуатации скорость деградации кристалла …
  • Гаджеты для домашней автоматики – Емкостной сенсорГаджеты для домашней автоматики – Емкостной сенсор
    Просмотров: 1407 Управление светодиодным освещением – Сенсор емкостной. Данный гаджет предназначен для управления освещением где необходимо включением освещение сенсорным прикосновением. Датчик позволяет управлять светодиодной нагрузкой в виде модулей или светодиодных лент …
  • Одноканальный емкостной сенсор – AT42QT1012Одноканальный емкостной сенсор – AT42QT1012
    Просмотров: 2181 Описание сенсора [wpdm_file id=242] Незаконченный проект, так-как сенсор не оправдал своего назначения, не рекомендую, просто выброшенные деньги. Особенности. • Количество сенсоров – один, режим переключения ( touch-on/touch-off ), а также программируемая …
  • Акриловый корпус для платы ch-4000Акриловый корпус для платы ch-4000
    Просмотров: 537 Плата ch-4000 подходит для монтажа в корпуса на дин рейку, но для домашней автоматики необходимо что-то другое, поэтому был разработан корпус из акрила который позволит создавать настольные и настенные устройства. Корпус …
  • REFERENCE CLOCK OUTPUT MODULEREFERENCE CLOCK OUTPUT MODULE
    Просмотров: 393 REFERENCE CLOCK OUTPUT MODULE Модуль формирования опорного тактового сигнала Модуль опорного тактового сигнала обеспечивает возможность посылать сигнал синхронизации на тактовый опорный выходной контакт или контакты (CLKR) в зависимости от …
  • Индикатор температурыИндикатор температуры
    Просмотров: 2513 Проект для начинающих, на демо плате BB-2T3D-01. Простой индикатор температуры. Проект никак не задумывался, просто на витрину магазин Ворон нужна была демонстрационная модель на макетной плате, чего нибудь работающего. Остановились на индикаторе …
  • Дисплей KD035C-3A подключение и управлениеДисплей KD035C-3A подключение и управление
    Просмотров: 604 Дисплей KD035C-3A производиться компанией SHENZHEN STARTEK ELECTRONIC TECHNOLOGY CO.,LTD Характеристики Параметр Спецификация Единицы измерения Размер дисплея 70.08(H)*52.56(V) (3.5inch) mm Тип дисплея TFT active matrix Цветовая гамма 65K/262K colors Разрешение …
  • Модуль CAN в микроконтроллерах PIC18Модуль CAN в микроконтроллерах PIC18
    Просмотров: 5379 Введение   CAN последовательный интерфейс связи, который эффективно поддерживает распределенное управление в реальном масштабе времени с высокой помехозащищенностью. Протокол связи полностью определен Robert Bosch GmbH, в спецификации требований …



Поделись этим!

Catcatcat

catcatcat

Development of embedded systems based on Microchip microcontrollers.

2 комментария для “Проект с использованием MCC часть 16

Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.