Xmega: Работа с дисплеем Winstar WH1602 на контроллере HD44780

Posted by Reason89 | Posted in , ,

 
    Разъяснять о дисплее ничего не буду, информации в сети просто уйма. Самый распространенный контроллер для LCD. Дисплее встретить можно везде и повсеместно. На момент подписания подобные дисплее 16х2 можно с китая заказать за 90 рублей за штуку.
    Подключаются все практически однотипно, единственный косяк есть в том что у некоторых моделей VCC и GND поменяны местами, если перепутать сгорает моментально.
    Изучал подобный дисплей еще в универе, тогда было проще) Макетка заранее настроена, все библиотеки подключены, печатаешь все согласно методичке и все работает)
    Решил подключить сей девайс к Xmega. Как подключать, включать подсветку, настраивать контрастность и выводить кириллицу найти не проблема.
    Моя первая и главная ошибка была в том, что я много времени убил на поиск готовой библиотеки, которых на самом деле не мало. Нашел даже для контроллеров Xmega Но любые попытки подключить уже что то готовое разбивались в пух и прах. То компилятору что то не нравилось, то не хватало какой то библиотеки и.т.д. В итоге плюнул, освоил с нуля документацию и начал писать сам. Совету вчитаться в команды и расшифровать их, а не в лоб использовать готовые.
 
    Второе на что следует обратить внимание это то, что дисплей мягко говоря заторможен. После любой отправленной ему команды необходимо выдерживать приличную паузу.
Смотрите даташит и ставите с запасом и не прогадаете.
Ну и собственно несколько функций для приятной работы по 8 битной шине данных:
Пытался выложить по как обычно через виджет, но он исковеркал код до неузнаваемости, итого выложу так.

Включение преобразований c типом float в Atmel Studio

Posted by Reason89 | Posted in , , ,

    На днях столкнулся с проблемой вывода числа с плавающей запятой на LCD дисплей WH1602.
    При преобразовании обычного десятичного числа, на LCD выводилось все как нужно.
long int Temp = 0x7777;
char st_Temp[6] = "";
itoa(Temp, st_Temp, 10);
LCD_Data(st_Temp[0]);
LCD_Data(st_Temp[1]);
LCD_Data(st_Temp[2]);
LCD_Data(st_Temp[3]);
    После преобразования в число с плавающей  запятой на WH1602 выводился знак вопроса и ряд пробелов.
long int Temp = 0x7777;
char st_Temp[10] = "";
float Temp_float = 0;
Temp_float = (float)Temp / 100; 
sprintf(st_Temp, "%01.2f", Temp_float );
LCD_Data(st_Temp[0]);
LCD_Data(st_Temp[1]);
LCD_Data(st_Temp[2]);
LCD_Data(st_Temp[3]);
LCD_Data(st_Temp[4]);
LCD_Data(st_Temp[5]);
    После долгих поисков проблемы, скачал DEV C++ и скомпилировал проект там с выводом в консоль. Все вывелось, как и было задумано.
    Получается проблема была в компиляторе Atmel Studio. Версия была у меня 6.0.1703
    Так как контроллеры Atmel сами по себе не умеют работать с числами с плавающей запятой, то такие преобразования выполняются сугубо программно.
    Функции преобразования типа float, такие как sprintf, ftoa, snprintf и.т.д. отнимают много ресурсов контроллера от того их использовать не рекомендуется и они по умолчанию отключены в Atmel Studio.
    Можно  постоянно делить число 10, и проверять результат деления больше или меньше он 10. Чтобы своевременно самому выставить запятую, но для этого нужно городить несколько циклов и условий, а в ресурсах МК я не был ограничен.
     Потому для решения проблемы я скачал Atmel Studio 6.2( в 6.0.1703 такие опции я не нашел).
    Переходим на вкладку параметров проекта ALT+F7.
    В меню AVR/GNU linker- General клацаем галочку на против Use vprintf library
     Затем в AVR/GNU linker- Library добавляем 2 библиотеки: printf_flt и scanf_flt
    Компилируем проект, получаем пару предупреждений об использовании типа float и собственно все. На LCD результат выводит с плавающей запятой.

Счетчик реального времени(RTC) в Xmega.

Posted by Reason89 | Posted in , ,


    В микроконтролерах Xmega используется 16 битный счетчик реального времени(RTC) с одним каналом сравнения. Счетчик реального времени обычно используется в экономичных режимах работы МК с целью сохранения счета времени и возобновления активной работы МК через регулярные интервалы времени. Максимальное время отсчета счетчика 18 с лишним часов. Счетчик реального времени имеет предмасштабирование, с максимальным коэффициентом 1024. Коэффициент предмасштабирования можно задать в регистре CTRL.
    RTC - асинхронный модуль. Он синхронизируется от отдельного источника, который никак не связан с сигналом основной системной синхронизации и другими производными от него сигналами.  RTC может тактироваться от: внутреннего RC-генератора ультранизкой мощности на 32 кГц, внутренний подстраиваемый RC-генератор на 32 кГц( более точный, но и более прожорливый), внешний кварцевый генератор на 32.768 кГц (самый точный).
    RTC формирует событие или прерывание по достижению определенного или максимального значения(т.е. по переполнению). Счетчик реального времени может генерировать прерывания, по переполнению и по сравнению.
    Прерывание по переполнению имеют постоянную частоту при постоянном значении периода (PER). Регистр сравнения (COMP) позволяет изменять частоту прерываний без изменения периода или перезапуска регистра счетчика (CNT).
    Система событий не работает в спящих режимах глубже нерабочего режима (Idle).
    Векторы прерываний RTC:
OVF_vect Вектор прерывания по переполнению счетчика реального времени
PER_vect Вектор прерывания по совпадению в счетчике реального времени
    Функция инициализации RTC:

void RTC_init()
{
    CLK.RTCCTRL = CLK_RTCEN_bm+CLK_RTCSRC_RCOSC_gc;    // Включение и настройка на частоту 1кГц от внутреннего генератора 32кГц
    RTC.PER = 264;                                    // Заносим значение вершины счета.(До какого значения считать)
    RTC.CNT = 0;                                    // Обнуляем счетчик. В этом регистре хранится значение счетчика реального времени.
    RTC.INTCTRL = 0x03;                                // Включаем прерывания. Уровень прерываний высокий
}

RTC.CTRL = 0x01;                                    // Включение счетчика реального времени без предделителя, при 0x00 RTC выключен
                                                    // В этот регистр заносится коэффициент деления при включении RTC

Прерывания в Xmega

Posted by Reason89 | Posted in , ,


     В семейсте Xmega добавлена разветвленная система прерываний. Дл каждого прерывания может быть задано 4 уровня приоритета прерываний(High (высокий), Medium (средний),Low (низкий) и Off (выключенный). Плюс есть несколько не маскируемых прерываний, на вроде отказа внешней частоты.
     При поступлении запроса на обслуживание прерывания с более высоким уровнем приоритета процесс обработки прерывания с более низким уровнем приостанавливается, и процессор начинает обрабатывать более значимый запрос. Запросы на прерывание, которым присвоен статус High, обслуживаются немедленно после поступления, даже если центральный процессор сильно загружен. Чтобы не пропал ни один из запросов, и все они были обслужены, пусть даже и с задержкой есть специальная процедура Round Robin , этакий своеобразный циклический алгоритм диспетчеризации.
    Общая команда для включения всех прерываний осталась неизменной:
sei();
    Далее необходимо включить все три уровня прерываний:
PMIC.CTRL |= PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm;
    Соответственно если нужно включить только низкий уровень прерываний, то код упрощается:
PMIC.CTRL |= PMIC_LOLVLEN_bm
    О более конкретной настройке PMIC.CTRL можно прочесть в мануале.
    Для всех переферийных прерываний уровень приоритета выставляется отдельно, в соответствующем регистре. В качестве примера назначи прерыванию по таймеру TCC0, самый высокий уровень прерываний:
TCC0.INTCTRLA = 0x03;
    а для внешнего прерывания на порт ввода-вывода поставим самый низкий уровень прерываний:
PORTA.INTCTRL = 0x01;
    Для каждого порта может быть объявленно только 2 прерывания, int0 и int1:
PORTA.DIR = 0x00;
PORTA.INT0MASK = 0x01;
PORTA.INT1MASK = 0x02;
    Далее для корректной работы прерываний, необходимо подтянуть вывод порта:
PORTA.PIN1CTRL= PORT_OPC_WIREDANDPULL_gc;
PORTA.PIN2CTRL= PORT_OPC_WIREDANDPULL_gc;
    Так же можно настроить по какому из фронтов будет срабатывать прерывание, в качестве примера приведем срабатывание по заднему фронту:
PORTA.PIN1CTRL = PORT_ISC_FALLING_gc;
PORTA.PIN2CTRL = PORT_ISC_FALLING_gc;
     После того, как правильно настроили работу прерываний, необходимо написать обработчки этого прерывания:
ISR(PORTA_INT0_vect)
{
   //Code
}
    В Xmega огромное количество всевозможных прерываний, как по приему и передаче данных по всевозможным протоколам, так и по переполнению и совпаднию таймеров. Гибкая настройка позволяет реализовать практически любые свои потребности.

ЦАП в XMEGA(DAC)

Posted by Reason89 | Posted in , ,

    В микроконтроллерах есть высокоскоростные 12-разрядные аналоговые модули. В дополнении к АЦП и аналоговым компараторам, есть еще и высокопроизводительные цифроаналогвые преобразователи.
    Разрядность ЦАПа XMEGA 12 бит, скорость преобразования — до 1 Мбит/с. ЦАП получает частоту с периферийной тактовой частоты, запуск на преобразование могут осуществлять различные периферийные модули, подключенные к системе событий(Event System). Есть функция формирования нулевого выходного напряжения. Обычно все ЦАПы не отличаются линейностью, когда выходное напряжение в районе нуля. Для этого в  XMEGA есть два регистра, в которые можно записывать 7-битные калибровочные данные, для более точного выставления напряжения.
     Преобразования ЦАП инициируется либо записью значения во входные регистры ЦАП, либо поступлением события от Event System. Данные для преобразования во входные регистры можно записывать как из программы, так и через DMA. Выход с ЦАП может быть выполнен двумя способами. В одном случае один линейный выход на выводе микроконтроллера. В другом два независимых выхода на двух выводах микроконтроллера. В результате два канала ЦАП могут работать независимо друг от друга и выдавать два аналоговых сигнала, различающихся как по амплитуде, так и по частоте.
    В XMEGA отдельные регистры для записи входных данных на выдачу в оба канала. Выход ЦАП можно подключать внутри кристалла к другим узлам, таким как АЦП или к компаратору.
    Привожу самый простой пример работы ЦАПа, программа для микроконтроллера atxmega32a4. Пример просто выводит на вывод микроконтроллера половину питания AVCC.
volatile int Voltage = 0x7F;

void dac_init()
{
    DACB.CTRLC = ( DACB.CTRLC & ~DAC_REFSEL_gm) | DAC_REFSEL_AVCC_gc; // Используем AVCC
    DACB.CTRLB = ( DACB.CTRLB & ~DAC_CHSEL_gm ) | DAC_CHSEL_SINGLE_gc; // Используем один канал ЦАП
    DACB.CTRLA = DAC_CH0EN_bm | DAC_ENABLE_bm;
}

void DACB_out(int Voltage)
{
   //DACB.CH0DATA = Voltage;  // Можно выводить значение из этой переменной
   DACB.CH0DATAH = 0x0F;    // А можно в ручную заполнять значения регистров
   DACB.CH0DATAL = 0xFF;
   while (!DACB.STATUS & DAC_CH0DRE_bm);
}

void dac_init();
void DACB_out(int Voltage);

int main(void)
{
    PORTB.DIR = 0xFF;//0x08;
    PORTB.PIN3CTRL = PORT_ISC_INPUT_DISABLE_gc;
    dac_init();
    
   while(1)
   {
      DACB_out(Voltage);
   }
}

    В регистре CTRLC настраивается источник опорного напряжения:
DACB.CTRLC = ( DACB.CTRLC & ~DAC_REFSEL_gm) | DAC_REFSEL_AVCC_gc;

    В регистре CTRLA необходимо разрешить канал или каналы, который мы будем использовать, и включить сам ЦАП
DACB.CTRLA = DAC_CH0EN_bm | DAC_ENABLE_bm;
     В регистре CTRLB выбирается режим, в котором будет работать ЦАП, т.е. однолинейный или двухлинейный.
DACB.CTRLB = ( DACB.CTRLB & ~DAC_CHSEL_gm ) | DAC_CHSEL_SINGLE_gc;
     Соответственно регистры в которые заносится значение. Не стоит забывать, что ЦАП 12 разрядный.
DACB.CH0DATAH = 0x0F; 
DACB.CH0DATAL = 0xFF;
     И в завершении не стоит забывать отключать от порта цифровой вывод.
PORTB.PIN3CTRL = PORT_ISC_INPUT_DISABLE_gc;