ШИМ-генератор ATMega8+LCD+кнопки

Обсуждаем контроллеры компании Atmel.
Аватара пользователя
АлександрЛ
Друг Кота
Сообщения: 43888
Зарегистрирован: Пн ноя 30, 2009 03:00:01
Откуда: Нерезиновая

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение АлександрЛ »

forregister84 писал(а):До энкодера руки не дошли.
А, может быть, дойдут? :)) :)) Как-то кажется, что, хотя бы частоту, энкодером менять проще.. :dont_know:
Реклама
forregister84
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вт авг 23, 2022 14:44:25

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение forregister84 »

А вот и схема:
Вложения
_Kicad_User_Lib.zip
(450.5 КБ) 138 скачиваний
ATMega8_PWM_LCD_KiCad6.zip
(146.53 КБ) 137 скачиваний
ATMega8_PWM_LCD.pdf
(74.2 КБ) 154 скачивания
Реклама
OKF
Это не хвост, это антенна
Сообщения: 1393
Зарегистрирован: Вт июн 07, 2011 08:03:18

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение OKF »

[uquote="АлександрЛ",url="/forum/viewtopic.php?p=4280914#p4280914"]Как-то кажется, что, хотя бы частоту, энкодером менять проще.. :dont_know:[/uquote]
Ну конечно, нужно делать по уму, а не тяп-ляп.)
forregister84
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вт авг 23, 2022 14:44:25

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение forregister84 »

Прошивка для энкодера будет очень нескоро. Пока только схема:
Вложения
ATMega8_PWM_LCD_E.pdf
(84.42 КБ) 125 скачиваний
ATMega8_PWM_LCD_E_KiCad6.zip
(33.68 КБ) 127 скачиваний
Реклама
Эиком - электронные компоненты и радиодетали
forregister84
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вт авг 23, 2022 14:44:25

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение forregister84 »

Кнопка Mode на PB0 (так удобнее на моей макетке). Исправлен глюк: нужно было нажать 2 раза для увеличения 4000 -> 4001 Гц

Добавлено after 5 minutes 19 seconds:
ШИМ-генератор с LCD, 2-мя энкодерами и кнопкой

Энкодер с кнопкой NONAME.
12 импульсов, 12 щелчков на 1 оборот
При вращении вручную самые короткие импульсы около 10 мс.
1 энкодер нормальный, второй с очень сильным дребезгом. Подтяжка 10 кОм + фильтр 10 кОм + 47 нФ
Фронты 10-90%: нарастание 2мс/ спад 1 мс.

Самое устойчивое состояние - когда оба сигнальных вывода не соединены с общим (11).

Вращение по часовой стрелке (CW):
AB
11
01
00
10
11

Вращение против часовой стрелке (CCW):
AB
11
10
00
01
11

Шаг частоты 1/10/100/1000 Гц. Шаг ШИМ 0,01/ 0,1 / 1 / 5 %. Переключение кнопкой энкодера по кругу.
(нужно добавить мигание соответствующего разряда неск. сек.)

2-х канальный ШИМ с энкодером будет позже.
Вложения
ATMega8_PWM_LCD_E.pdf
(86.14 КБ) 131 скачивание
ATMega8_PWM_LCD_E_KiCad6.zip
(117.68 КБ) 123 скачивания
ATMega8_PWM_LCD_E_083_AS7.zip
(184.58 КБ) 138 скачиваний
ATMega8_PWM_LCD.pdf
(74.97 КБ) 112 скачиваний
ATMega8_PWM_LCD_KiCad6.zip
(147.3 КБ) 122 скачивания
ATMega8_PWM_LCD_082_AS7.zip
(177.84 КБ) 128 скачиваний
ATMega8_PWM_2CH_LCD_082_AS7.zip
(178.98 КБ) 126 скачиваний
Реклама
Dimon456
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение Dimon456 »

А что одним шимом ограничились-то?, развивайте дальше тему, частотомер, генератор, вольтметр и т.п.

Вопрос, за чем использовать прерывания? Для чего?
На сколько мне известно особенностью работы блока сравнения в режимах, предназначенных для формирования ШИМ-сигналов, является двойная буферизация записи в регистры сравнения. Она заключается в том, что записываемое число на самом деле сохраняется в специальном буферном регистре. А изменение содержимого регистра сравнения происходит только при достижении счетчиком максимального значения. Вам что, аппаратного ШИМ не достаточно?
Реклама
forregister84
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вт авг 23, 2022 14:44:25

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение forregister84 »

Dimon456 Изменение делителя таймера посредине импульса насколько я понял исказит сигнал. Поэтому он меняется в начале периода.
ICR1 в 2-х канальном ШИМ без буфферезации.
Еще не все варианты глюков проверил.
akl
Друг Кота
Сообщения: 4445
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение akl »

forregister84 писал(а):...1 энкодер нормальный, второй с очень сильным дребезгом. Подтяжка 10 кОм + фильтр 10 кОм + 47 нФ...
Дребезг значительно уменьшается при уменьшении номиналов R3...R9 до 1...3кОм чтобы привести в соответствие с типовыми характеристиками на контактные энсодеры.
СпойлерИзображение
Вместо такой картинки при номинале 10к
СпойлерИзображение
при номинале 1к будете видеть
СпойлерИзображение
Вложения
valcoder 001_1.jpg
(46.79 КБ) 302 скачивания
Валкодер3.PNG
(122.38 КБ) 291 скачивание
энкодер_ток.png
(10.53 КБ) 299 скачиваний
forregister84
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вт авг 23, 2022 14:44:25

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение forregister84 »

akl спасибо. А можно ссылку на datasheet ? А то у Bourns PEC12R минимального тока нет. У меня были подозрения насчет нехватки тока для контактов. RC-фильтр помог и я на этом успокоился.
forregister84
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вт авг 23, 2022 14:44:25

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение forregister84 »

С моими энкодерами с подтягивающими резисторами 2 кОм лучше не стало. Если вручную быстро крутить дребезг все равно очень сильный.
(энкодеры старые взял с куском какой-то платы). Фильтр все равно нужен. Оставил 2 кОм т.к. это более корректно.

Макетка_ATMega8
https://img.radiokot.ru/files/150397/2xja9u4cf4.JPG

Осциллограммы:

Медленное вращение энкодера без фильтра
https://img.radiokot.ru/files/150397/2xjabdm61z.png

Быстрое:
https://img.radiokot.ru/files/150397/2xjabcupue.png
https://img.radiokot.ru/files/150397/2xjabddm5j.png
На выходе фильтра:
https://img.radiokot.ru/files/150397/2xjabd4ruh.png
veso74
Поставщик валерьянки для Кота
Сообщения: 1908
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение veso74 »

Измените метод/алгоритм для механического энкодера с simple state machine. Никогда, ни с каким типом енкодера не ошибается (даже с поврежденным "зубом" - просто пропускает поврежденный зуб). Назад во времени для себя портировал код с Arduino на AVR, на PIC, с/без прерывания, везде успешно работает. Почти никогда не подключаю даже конденсатори. О более сложных системах debounce речь вообще не идет - нет необходимости.

Rotary encoder handler for Arduino. v1.1, 2011 Ben Buxton
forregister84
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вт авг 23, 2022 14:44:25

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение forregister84 »

veso74 - спасибо. Это табличный метод. Оставлю на потом.

добавлено мигание разряда при изменении шага.
Вложения
ATMega8_PWM_LCD_E.pdf
(85.61 КБ) 104 скачивания
ATMega8_PWM_LCD_E_085_AS7.zip
(187.1 КБ) 121 скачивание
ATMega8_PWM_2CH_LCD_E_085_AS7.zip
(187.32 КБ) 116 скачиваний
forregister84
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вт авг 23, 2022 14:44:25

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение forregister84 »

исправлено: атомарный доступ к T1_TOP, T1_OCR (иногда устанавливался завышенный ШИМ)
Вложения
ATMega8_PWM_LCD_E_086_AS7.zip
Dead Time 0, 1, 2 такта F_CPU (легко перекомпилировать на //#define PWM_MAX 10000 //100%)
(187.52 КБ) 112 скачиваний
ATMega8_PWM_2CH_LCD_E_086_AS7.zip
Dead Time 0...1, 1...2, 2..3 такта F_CPU
(260.44 КБ) 129 скачиваний
forregister84
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вт авг 23, 2022 14:44:25

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение forregister84 »

Уменьшены до минимума глитчи на ВЧ и НЧ при изменении частоты.
Те, кто свято верит в "двойная буферизация записи в регистры сравнения"
не учитывают что между записью в OCR1A и OCR1B проходит 2 такта. В это время
может прийти конец периода и OCR1A обновится, а OCR1B обновится в следующем
периоде. Это приводит к глитчам, типа растягивание импульса на 2 периода и т.д.
Особенно неприятно, когда это происходит при резком изменении частоты, например 300 - 1300 Гц.
Поэтому на низкой частоте запись в регистры в начале периода в прерывании.
На ВЧ шаг периода 1 такт и глитчи не более 1 такта.

2-х канальный ШИМ с энкодером будет позже.
Вложения
LF_glitch.zip
(219.73 КБ) 113 скачиваний
HF_glitch.zip
(90.68 КБ) 117 скачиваний
ATMega8_PWM_LCD_E_087_AS7.zip
(188.47 КБ) 135 скачиваний
forregister84
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вт авг 23, 2022 14:44:25

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение forregister84 »

ATMega8_PWM_LCD_E_087_AS7
Небольшие исправления, ничего не меняющие, но быдлокодинга с TIFR и TIMSK меньше.

ATMega8_PWM_2CH_LCD_E_086a_AS7
2-х канальный ШИМ с энкодером:
Исправлено: при увеличении частоты ICR1 может быть меньше TCNT1 и тогда счетчик считает до 0xFFFF.
Исправлено с помощью записи 1 в TCNT1, что приводит к глитчу ВЧ.
Глитч НЧ при изменении делителя остался.
Вложения
ATMega8_PWM_LCD_E_087_AS7.zip
(188.45 КБ) 114 скачиваний
ATMega8_PWM_2CH_LCD_E_086a_AS7.zip
(261.61 КБ) 121 скачивание
Glitch_E_086_2CH_HF.zip
(191.61 КБ) 106 скачиваний
Glitch_E_086a_2CH_HF.zip
(306.44 КБ) 113 скачиваний
Glitch_E_086a_2CH_LF.zip
(159.81 КБ) 114 скачиваний
forregister84
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вт авг 23, 2022 14:44:25

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение forregister84 »

Вышла небольшая накладочка... :(
Исправленные версии:

Добавлено after 20 minutes 18 seconds:
Точная NOP-синхронизация с началом периода. Глитч НЧ при изменении делителя остался.
Вложения
ATMega8_PWM_LCD_E_087a_AS7.zip
(190.05 КБ) 106 скачиваний
ATMega8_PWM_2CH_LCD_E_087a_AS7.zip
(263.09 КБ) 100 скачиваний
E_087_delays_16Mhz.zip
(216.91 КБ) 111 скачиваний
E_087a_1Mhz_2CH_sync.zip
(747.39 КБ) 106 скачиваний
E_087a_1Mhz_sync.zip
(234.9 КБ) 98 скачиваний
ATMega8_PWM_LCD_E_087_AS7.zip
(188.48 КБ) 122 скачивания
ATMega8_PWM_2CH_LCD_E_086a_AS7.zip
(262.35 КБ) 120 скачиваний
forregister84
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вт авг 23, 2022 14:44:25

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение forregister84 »

Два поста слились в один. Точная NOP-синхронизация с началом периода это версия 087a
forregister84
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Вт авг 23, 2022 14:44:25

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение forregister84 »

Увеличил период мигания, т.к. даже пр +5C LCD медленно обновляется.
Вложения
ATMega8_PWM_LCD_E_087a_AS7.zip
(190.63 КБ) 119 скачиваний
ATMega8_PWM_2CH_LCD_E_087a_AS7.zip
(263.74 КБ) 103 скачивания
Demiurg
Это не хвост, это антенна
Сообщения: 1480
Зарегистрирован: Ср июн 25, 2008 15:19:44
Контактная информация:

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение Demiurg »

Символьные ЖКИ-дисплеи медленные. Если не нужно выводить динамику типа индикатора уровня, спектроанализатора, то есть следующий способ:

Итак. Символьные дисплеи на контроллере HD44780 довольно медлительные. Команда очистки дисплея длится примерно 1600 мкс. Плюс временные интервалы, которые нужно выдерживать между отправками символов либо адресов строк. Есть два варианта, Опрос флага готовности BF, либо выдерживать временные интервалы. Суммируя все это, можно реализовать работу с сивольными ЖКИ дисплеями на контроллерах HD44780 следующим образом:

В ОЗУ отводим буфер. Число символов в строке * количество строк. При 20х4 получаем буфер размером 80 байт. И теперь алгоритм работы с дисплеем будет выглядеть так:

Пункт 1. Инициализация дисплея. Инициализация нужных режимов. Пункт 2. По готовности дисплея, работает автомат, каждые 1 мс. Отправка адреса текущей строки. Пункт 3. Отправка символа. Инкремент индекса указателя на символ. Как только значение указателя на символ >= символов в строке, индекс указателя на символ в ноль, инкремент индекса указателя на следующий адрес строки, если >= кол-ва строк, сброс на ноль индекса указателя на адреса строк. Пункт 2. То есть, адреса и символы отправляются каждые 1 мс. При дисплее 20х4 весь цикл занимает 84 мс.

Команда очистки дисплея теперь не нужна. Мы делаем очистку буфера дисплея.

char_display.h
Спойлер

Код: Выделить всё

#ifndef CHAR_DISPLAY_H

#define CHAR_DISPLAY_H

#include "char_display.h"

#include "main_def_func.h"

//==================
#define LCD             0
#define VFD             1

// Тип дисплея. ЖКИ LCD или вакуумно-люминесцентный VFD.
#define TYPE_DISPLAY    VFD // LCD // 
//==================

//==================
// LCD Data Port
#define DATA_PORT       PORTC
#define DATA_PIN        PINC
#define DATA_DDR        DDRC

// LCD Control Port
#define CMD_PORT        PORTC
#define CMD_PIN         PINC
#define CMD_DDR         DDRC

// Строб.
#define EN_PORT         PORTC
#define EN_DDR          DDRC

#define EN              2

// Команда\данные.
#define RS_PORT         PORTC
#define RS_DDR          DDRC

#define RS              3
//==================

//==================
#define Line1           0x80 // Адрес первой строки.
#define Line2           0xC0 // Адрес второй строки.
#define Line3           0x94 // Адрес третьей строки.
#define Line4           0xD4 // Адрес четвертой строки.
//==================

//==================
#define DRV_LCD_TIME    1
//==================

//==================
#if (TYPE_DISPLAY==VFD)
extern u08 bright; // Значение яркости VFD.
// 3 - 25%
// 2 - 75%
// 1 - 50%
// 0 - 100%
#endif
//==================

//==================
#define QUANT_USERS_CHARS 4

#define ARROW_RIGHT 2
#define ARROW_LEFT 3
//==================

//==================
void lcd_io_in (void);
void lcd_send_nibble (u08 lcd_data);
void lcd_send_byte (u08 lcd_data);
void lcd_send_com_nibble (u08 lcd_data);
void lcd_send_com (u08 lcd_data);
void lcd_send_data (u08 lcd_data);
//==================

//==================
bool char_dsp_init (void);
//==================

//==================
void def_users_chars (u08 __flash *ptr);
//==================

//==================
#define POSITION_MAX_X    20   // Количество символов в строке.
#define POSITION_MAX_Y    4    // Количество строк дисплея.

extern char dsp_buf [];

#define LineBuf1          dsp_buf
#define LineBuf2          dsp_buf+POSITION_MAX_X
#define LineBuf3          dsp_buf+(POSITION_MAX_X*2)
#define LineBuf4          dsp_buf+(POSITION_MAX_X*3)
//==================

//==================
#ifdef __PROJECT_MODE_WORK__
#define DSP_INIT_TIME 40
#endif

#ifdef __PROJECT_MODE_DEBUG__
#define DSP_INIT_TIME 4
#endif
//==================

//==================
extern void clr_dsp_buf (void);

extern void init_dsp_buf (void);
//==================

//==================
#define Clr_String(y, x, n) _clr_string(((y)-1)*POSITION_MAX_X+((x)-1), (n))
void _clr_string (u08 x, u08 n);
//==================

//==================
extern u08 __flash string_azbuka [];

void test_out_text (void);
//==================

//==================
enum
{
   DRV_CHAR_DSP_INIT_1 = 0,
   DRV_CHAR_DSP_INIT_2,
   DRV_CHAR_DSP_SEND_ADDR,
   DRV_CHAR_DSP_SEND_CHAR,
};
//------------------------------------------------------------------------
void drv_char_dsp (void);

void drv_char_dsp_init_1 (void);
void drv_char_dsp_init_2 (void);
void drv_char_dsp_send_addr (void);
void drv_char_dsp_send_char (void);
//------------------------------------------------------------------------
u08 get_char_dsp_state (void);
//==================

#endif
char_display.c
Спойлер

Код: Выделить всё

//==================
#include "char_display.h"
//==================

//==================
// Алгоритм работы модуля дисплея:
// Есть буфер дисплея. Размер буфера равен кол-во символов*кол-во строк.
// Обновление дисплея осуществляется посимвольно, раз в 1 мс. Полное
// обновление дисплея происходит за
// кол-во символов*кол-во строк + кол-во строк (адреса строк).
// Если дисплей 20х4, то полное обновление происходит за 20*4+4=84 мс.
//==================

//==================
static u08 _drv_char_dsp;

static u08 position_x;
static u08 position_y;

u08 __flash lines [4] = {0x80, 0xC0, 0x94, 0xD4};

   static soft_timer ST_DRV_CHAR_DSP;
//==================

//==================
#if (TYPE_DISPLAY == LCD)

u08 __flash table_rus_chars [64] =
{
  0x41,0xa0,0x42,0xa1,0xe0,0x45,0xa3,0xa4,
  0xa5,0xa6,0x4b,0xa7,0x4d,0x48,0x4f,0xa8,
  0x50,0x43,0x54,0xa9,0xaa,0x58,0xe1,0xab,
  0xac,0xe2,0xad,0xae,0x62,0xaf,0xb0,0xb1,
  0x61,0xb2,0xb3,0xb4,0xe3,0x65,0xb6,0xb7,
  0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0x6f,0xbe,
  0x70,0x63,0xbf,0x79,0xe4,0x78,0xe5,0xc0,
  0xc1,0xe6,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
};

u08 __flash string_azbuka [] = "абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ";

//------------------------------------------------------------------------

#elif (TYPE_DISPLAY == VFD)

u08 __flash table_users_chars [8 * QUANT_USERS_CHARS]  = // Таблица пользовательских символов.
{
0x00, 0x04, 0x0E, 0x15, 0x15, 0x0E, 0x04, 0x04, // Ф
0x00, 0x10, 0x10, 0x10, 0x1E, 0x11, 0x11, 0x1E, // Ь
0x00, 0x08, 0x0C, 0x1E, 0x1F, 0x1E, 0x0C, 0x08,
0x00, 0x02, 0x06, 0x0F, 0x1F, 0x0F, 0x06, 0x02,
};
//------------------------------------------------------------------------

//------------------------------------------------------------------------
u08 __flash table_rus_chars [32] = // Таблица кириллицы. VFD поддерживает только
// заглавные русские буквы. И не все. Ф и Ь в таблице пользовательских символов.
{
//АБВГДЕЖЗ
0x41, 0x80, 0x42, 0x92, 0x81, 0x45, 0x82, 0x83,
//ИЙКЛМНОП
0x84, 0x85, 0x4B, 0x86, 0x4D, 0x48, 0x4F, 0x87,
//РСТУФХЦЧ
0x50, 0x43, 0x54, 0x88, 0x00, 0x58, 0x89, 0x8A,
//ШЩЪЫЬЭЮЯ
0x8B, 0x8C, 0x8D, 0x8E, 0x01, 0x8F, 0xAC, 0xAD,
};

#endif
//==================

//==================
void lcd_io_in (void)
{
   DATA_DDR = DATA_DDR & 0x0F;
   DATA_PORT = DATA_PORT & 0x0F;
}
//------------------------------------------------------------------------

//------------------------------------------------------------------------
void lcd_send_nibble (u08 lcd_data)
{
   set_bit (CMD_PORT, EN);
   DATA_PORT = (DATA_PORT & 0x0F) | (lcd_data & 0xF0);
   asm("rjmp ($/2+1)*2"); // Такой своеобразный ассемблер в IAR/
   asm("rjmp ($/2+1)*2");
   asm("rjmp ($/2+1)*2");
   asm("rjmp ($/2+1)*2");
   asm("rjmp ($/2+1)*2");
   clr_bit (CMD_PORT, EN);
   asm("rjmp ($/2+1)*2");
   asm("rjmp ($/2+1)*2");
   asm("rjmp ($/2+1)*2");
   asm("rjmp ($/2+1)*2");
   asm("rjmp ($/2+1)*2");
}
//------------------------------------------------------------------------

//------------------------------------------------------------------------
void lcd_send_byte (u08 lcd_data)
{
   DATA_DDR = (DATA_DDR | 0xF0);
   lcd_send_nibble (lcd_data);
   lcd_send_nibble (lcd_data << 4);
}
//------------------------------------------------------------------------

//------------------------------------------------------------------------
void lcd_send_com_nibble (u08 lcd_data)
{
   clr_bit (CMD_PORT, RS);
   DATA_DDR = (DATA_DDR | 0xF0);
   lcd_send_nibble (lcd_data);
   lcd_io_in ();
}
//------------------------------------------------------------------------

//------------------------------------------------------------------------
void lcd_send_com (u08 lcd_data)

{
   clr_bit (CMD_PORT, RS);
   lcd_send_byte (lcd_data);
   lcd_io_in ();
}
//------------------------------------------------------------------------

//------------------------------------------------------------------------
void lcd_send_data (u08 lcd_data)
{
   set_bit (CMD_PORT,RS);

#if (TYPE_DISPLAY == LCD)
      if (lcd_data == 0xA8)
      {
         lcd_data = 0xA2; //буква 'Ё' 
      }
      else if (lcd_data ==0xB8)
      {
         lcd_data = 0xB5; //буква 'ё'
      }
#endif

   if (lcd_data >= 0xC0)
   {
      lcd_data = table_rus_chars [lcd_data - 0xC0];
   }

   lcd_send_byte (lcd_data);
   lcd_io_in ();
}
//==================

//==================
 // Инициализация дисплея.

bool char_dsp_init (void)
{
   static u08 _char_dsp_init;

#if (TYPE_DISPLAY == LCD)
   static u08 cnt;
#endif

   switch (_char_dsp_init)
   {
      case 0:
         set_soft_timer (ST_DRV_CHAR_DSP, DSP_INIT_TIME, 0); // Задержка. Повтора нет.
         _char_dsp_init = 1;
         return false;

      case 1:
         if (handle_soft_timer (ST_DRV_CHAR_DSP))
         {
            set_bit (EN_DDR, EN);
            set_bit (RS_DDR, RS);

#if (TYPE_DISPLAY == LCD)
            cnt = 0;

            set_soft_timer (ST_DRV_CHAR_DSP, 0, 5); // Немедленное исполнение, последующая задержка 5 мс.
            _char_dsp_init = 2;

#elif (TYPE_DISPLAY == VFD)

            // Так как VFD работает быстро, задержки не нужны.
            for (u08 i = 3; i > 0; i--)
            {
               lcd_send_com_nibble (0x30); // Установка 8-разрядного интерфейса.
            }

            lcd_send_com_nibble (0x20); // Установка 4-разрядного интерфейса.
            lcd_send_com (0x28 | 3); // 4-разрядный интерфейс. Двухстрочный режим. Яркость 25 %

            //   lcd_send_com(0x01); // Команда очистки дисплея.
            //   wait_5_ms ();

            lcd_send_com (0x06); // Инкремент счетчика адреса.
            lcd_send_com (0x0C); // Включение дисплея.

            def_users_chars (table_users_chars);

            return true;
#endif
         }
         return false;

#if (TYPE_DISPLAY == LCD)
      case 2:
         if (handle_soft_timer (ST_DRV_CHAR_DSP))
         {
            if (cnt < 3)
            {
               lcd_send_com_nibble (0x30); // Установка 8-разрядного интерфейса.
               cnt++;
               return false;
            }

            if (cnt == 3)
            {
               lcd_send_com_nibble (0x20); // Установка 4-разрядного интерфейса.
               delay_us (50);

               lcd_send_com (0x28); // 4-разрядный интерфейс. Двухстрочный режим.
               delay_us (50);

               lcd_send_com(0x01); // Команда очистки дисплея.
               cnt++;
               return false;
            }

            if (cnt == 4)
            {
               lcd_send_com (0x06); // Инкремент счетчика адреса.
               delay_us (50);

               lcd_send_com (0x0C); // Включение дисплея.
               delay_us (50);
               return true;
            }
         }
         return false;
#endif
   }

   return false;
}
//==================

//==================
void def_users_chars (u08 __flash *ptr)
{
   lcd_send_com (1<<6);

   u08 a;
   u08 b;

   for (a = QUANT_USERS_CHARS; a > 0; a--)
   {
      for (b = 8; b > 0; b--)
      {
         lcd_send_data (*ptr);
         ptr++;

#if (TYPE_DISPLAY == LCD)
         delay_us (50);
#endif

      }
   }
}
//==================

//==================
// Очистка буфера дисплея.

char dsp_buf [POSITION_MAX_X * POSITION_MAX_Y];

void clr_dsp_buf (void)
{
   u08 i;

   for (i = 0; i < POSITION_MAX_X * POSITION_MAX_Y; i++)
      dsp_buf [i] = 0x20;

   init_dsp_buf (); // Переинициализация модуля дисплея.
}
//==================

//==================
// Переинициализация модуля дисплея.
// Так как модуль ЖКИ работает с обновлением, то при выводе новой информации
// переинициализация модуля дисплея, чтобы обновление началось заново.

void init_dsp_buf (void)
{
   _drv_char_dsp = DRV_CHAR_DSP_INIT_2;
}
//==================

//==================
// Очистка определенного участка буфера дисплея. Формат:
// Номер строки, номер знакоместа, кол-во очищаемых знакомест.

void _clr_string (u08 x, u08 n)
{
   while (n--) dsp_buf [x++] = ' ';

//   init_dsp_buf (); // Переинициализация модуля дисплея.
}
//==================

//==================
//void test_out_text (void)
//{
/*
// Тестовый вывод текста в буфер.
// Вариант 1 вывода текста.
u08 i = 0;
u08 j = 0;

while (string_azbuka [j])
{
   dsp_buf [i++] = string_azbuka [j++];
}

clr_dsp_buf ();
*/
//------------------------------------------------------------------------
// Вариант 2 вывода текста.
// Примечание: в параметрах функции Print_Buf количество символов не должно
// превышать кол-ва символов на строку. Но в данном случае точно известно,
// что позиция первого символа начинается с нулевого адреса буфера дисплея
// и кол-во символов не превышает 20*4.

//Print_Buf (1, 1, "абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ");

//      Print_Buf (1, 1, "абвгдеёжзийклмнопрст");
//      Print_Buf (1, 2, "уфхцчшщъыьэюяАБВГДЕЁ");
//      Print_Buf (1, 3, "ЖЗИЙКЛМНОПРСТУФХЦЧШЩ");
//      Print_Buf (1, 4, "ЪЫЬЭЮЯ");
//}
//==================

//==================
void drv_char_dsp (void)
{
   u08 data;

   switch (_drv_char_dsp)
   {
      case DRV_CHAR_DSP_INIT_1:
         if (char_dsp_init ())
         {
            clr_dsp_buf ();
            Set_Event (EV_ID_CHAR_DSP_RUN, USER_EVENT);
            _drv_char_dsp = DRV_CHAR_DSP_INIT_2;
         }
         break;

      case DRV_CHAR_DSP_INIT_2:
         position_x = 0;
         position_y = 0;

         set_soft_timer (ST_DRV_CHAR_DSP, 0, 1); // Немедленное исполнение. Повтор.

         _drv_char_dsp = DRV_CHAR_DSP_SEND_ADDR;
         break;

      case DRV_CHAR_DSP_SEND_ADDR:
         if (handle_soft_timer (ST_DRV_CHAR_DSP))
         {
            lcd_send_com (lines [position_y]);
            _drv_char_dsp = DRV_CHAR_DSP_SEND_CHAR;
         }
         break;

      case DRV_CHAR_DSP_SEND_CHAR:
         if (handle_soft_timer (ST_DRV_CHAR_DSP))
         {
         #if (TYPE_DISPLAY == LCD)
            data = dsp_buf [(position_y * POSITION_MAX_X) + position_x];

            if (data >= 0xC0)
            {
               data = table_rus_chars [data - 0xC0];
            }

            lcd_send_data (data);
            position_x++;

            if (position_x >= POSITION_MAX_X)
            {
               position_x = 0;

               position_y++;
               if (position_y >= POSITION_MAX_Y)
               {
                  position_y = 0;
               }

               _drv_char_dsp = DRV_CHAR_DSP_SEND_ADDR;
            }

         #elif (TYPE_DISPLAY == VFD)
            while (position_x < POSITION_MAX_X)
            {
               data = dsp_buf [(position_y * POSITION_MAX_X) + position_x];

               if (data >= 0xC0)
               {
                  data = table_rus_chars [data - 0xC0];
               }

               lcd_send_data (data);
               position_x++;
            }

            position_x = 0;

            position_y++;
            if (position_y >= POSITION_MAX_Y)
            {
               position_y = 0;

               char_dsp_init (); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            }

            _drv_char_dsp = DRV_CHAR_DSP_SEND_ADDR;

         #endif
         }
         break;
   }
}
//==================

//==================
u08 get_char_dsp_state (void)
{
   return _drv_char_dsp;
}
//==================
Пример старый, но рабочий. Неоднократно использовался как на своих поделках, так и в заказных проектах. По поводу VFD дисплея Futaba m204sd08aa. Это аналог контроллера HD44780. Но быстрый. Ему не требуются долгие временные интервалы, как у ЖКИ.

Делал одно устройство, отлаживал работу трансивера. Видео одного из тестов.
Вложения
1999788.jpeg
(76.11 КБ) 99 скачиваний
Последний раз редактировалось Demiurg Ср окт 26, 2022 19:02:40, всего редактировалось 1 раз.
Аватара пользователя
MLX90640
Опытный кот
Сообщения: 848
Зарегистрирован: Ср авг 03, 2022 05:22:56

Re: ШИМ-генератор ATMega8+LCD+кнопки

Сообщение MLX90640 »

весь цикл занимает 84 мс.
А 84 мс, извините, визуально уже заметно. Впрочем, на один символ тратится около 50 мкс при 8-битном интерфейсе, и 80 символов могут быть отправлены примерно за 4 мс., что и визуально незаметно, и не шибко то тормозит работу программы, да и выглядит намного-намного легче по объему программного кода и исходного текста.
И вовсе не всегда нужно перерисовывать именно все 4 строки сразу. Зачастую, при выводе строки придерживаются именно строчной структуры дисплея.
Ответить

Вернуться в «AVR»