Обсуждаем контроллеры компании Atmel.
Ответить

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

Ср авг 31, 2022 04:57:23

forregister84 писал(а):До энкодера руки не дошли.
А, может быть, дойдут? :)) :)) Как-то кажется, что, хотя бы частоту, энкодером менять проще.. :dont_know:

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

Ср авг 31, 2022 19:05:25

А вот и схема:
Вложения
_Kicad_User_Lib.zip
(450.5 KiB) Скачиваний: 61
ATMega8_PWM_LCD_KiCad6.zip
(146.53 KiB) Скачиваний: 73
ATMega8_PWM_LCD.pdf
(74.2 KiB) Скачиваний: 62

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

Чт сен 01, 2022 09:11:00

Как-то кажется, что, хотя бы частоту, энкодером менять проще.. :dont_know:

Ну конечно, нужно делать по уму, а не тяп-ляп.)

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

Вс сен 04, 2022 20:41:24

Прошивка для энкодера будет очень нескоро. Пока только схема:
Вложения
ATMega8_PWM_LCD_E.pdf
(84.42 KiB) Скачиваний: 59
ATMega8_PWM_LCD_E_KiCad6.zip
(33.68 KiB) Скачиваний: 68

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

Пн сен 12, 2022 11:29:04

Кнопка 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 KiB) Скачиваний: 58
ATMega8_PWM_LCD_E_KiCad6.zip
(117.68 KiB) Скачиваний: 66
ATMega8_PWM_LCD_E_083_AS7.zip
(184.58 KiB) Скачиваний: 70
ATMega8_PWM_LCD.pdf
(74.97 KiB) Скачиваний: 47
ATMega8_PWM_LCD_KiCad6.zip
(147.3 KiB) Скачиваний: 64
ATMega8_PWM_LCD_082_AS7.zip
(177.84 KiB) Скачиваний: 66
ATMega8_PWM_2CH_LCD_082_AS7.zip
(178.98 KiB) Скачиваний: 63

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

Пн сен 12, 2022 22:16:19

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

Вопрос, за чем использовать прерывания? Для чего?
На сколько мне известно особенностью работы блока сравнения в режимах, предназначенных для формирования ШИМ-сигналов, является двойная буферизация записи в регистры сравнения. Она заключается в том, что записываемое число на самом деле сохраняется в специальном буферном регистре. А изменение содержимого регистра сравнения происходит только при достижении счетчиком максимального значения. Вам что, аппаратного ШИМ не достаточно?

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

Пн сен 12, 2022 22:43:49

Dimon456 Изменение делителя таймера посредине импульса насколько я понял исказит сигнал. Поэтому он меняется в начале периода.
ICR1 в 2-х канальном ШИМ без буфферезации.
Еще не все варианты глюков проверил.

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

Вт сен 13, 2022 06:15:48

forregister84 писал(а):...1 энкодер нормальный, второй с очень сильным дребезгом. Подтяжка 10 кОм + фильтр 10 кОм + 47 нФ...
Дребезг значительно уменьшается при уменьшении номиналов R3...R9 до 1...3кОм чтобы привести в соответствие с типовыми характеристиками на контактные энсодеры.
СпойлерИзображение

Вместо такой картинки при номинале 10к
СпойлерИзображение

при номинале 1к будете видеть
СпойлерИзображение
Вложения
valcoder 001_1.jpg
(46.79 KiB) Скачиваний: 88
Валкодер3.PNG
(122.38 KiB) Скачиваний: 76
энкодер_ток.png
(10.53 KiB) Скачиваний: 77

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

Вт сен 13, 2022 17:36:34

akl спасибо. А можно ссылку на datasheet ? А то у Bourns PEC12R минимального тока нет. У меня были подозрения насчет нехватки тока для контактов. RC-фильтр помог и я на этом успокоился.

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

Ср сен 14, 2022 16:17:11

С моими энкодерами с подтягивающими резисторами 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

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

Ср сен 14, 2022 16:52:20

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

Rotary encoder handler for Arduino. v1.1, 2011 Ben Buxton

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

Пт сен 16, 2022 17:22:18

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

добавлено мигание разряда при изменении шага.
Вложения
ATMega8_PWM_LCD_E.pdf
(85.61 KiB) Скачиваний: 48
ATMega8_PWM_LCD_E_085_AS7.zip
(187.1 KiB) Скачиваний: 61
ATMega8_PWM_2CH_LCD_E_085_AS7.zip
(187.32 KiB) Скачиваний: 59

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

Вс сен 18, 2022 22:22:56

исправлено: атомарный доступ к 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 KiB) Скачиваний: 61
ATMega8_PWM_2CH_LCD_E_086_AS7.zip
Dead Time 0...1, 1...2, 2..3 такта F_CPU
(260.44 KiB) Скачиваний: 67

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

Чт сен 22, 2022 21:55:42

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

2-х канальный ШИМ с энкодером будет позже.
Вложения
LF_glitch.zip
(219.73 KiB) Скачиваний: 63
HF_glitch.zip
(90.68 KiB) Скачиваний: 64
ATMega8_PWM_LCD_E_087_AS7.zip
(188.47 KiB) Скачиваний: 70

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

Вс сен 25, 2022 12:22:58

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 KiB) Скачиваний: 58
ATMega8_PWM_2CH_LCD_E_086a_AS7.zip
(261.61 KiB) Скачиваний: 60
Glitch_E_086_2CH_HF.zip
(191.61 KiB) Скачиваний: 56
Glitch_E_086a_2CH_HF.zip
(306.44 KiB) Скачиваний: 57
Glitch_E_086a_2CH_LF.zip
(159.81 KiB) Скачиваний: 58

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

Вс окт 02, 2022 12:12:34

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

Добавлено after 20 minutes 18 seconds:
Точная NOP-синхронизация с началом периода. Глитч НЧ при изменении делителя остался.
Вложения
ATMega8_PWM_LCD_E_087a_AS7.zip
(190.05 KiB) Скачиваний: 52
ATMega8_PWM_2CH_LCD_E_087a_AS7.zip
(263.09 KiB) Скачиваний: 48
E_087_delays_16Mhz.zip
(216.91 KiB) Скачиваний: 52
E_087a_1Mhz_2CH_sync.zip
(747.39 KiB) Скачиваний: 48
E_087a_1Mhz_sync.zip
(234.9 KiB) Скачиваний: 47
ATMega8_PWM_LCD_E_087_AS7.zip
(188.48 KiB) Скачиваний: 62
ATMega8_PWM_2CH_LCD_E_086a_AS7.zip
(262.35 KiB) Скачиваний: 66

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

Пн окт 03, 2022 16:15:00

Два поста слились в один. Точная NOP-синхронизация с началом периода это версия 087a

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

Вт окт 25, 2022 16:03:52

Увеличил период мигания, т.к. даже пр +5C LCD медленно обновляется.
Вложения
ATMega8_PWM_LCD_E_087a_AS7.zip
(190.63 KiB) Скачиваний: 51
ATMega8_PWM_2CH_LCD_E_087a_AS7.zip
(263.74 KiB) Скачиваний: 53

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

Ср окт 26, 2022 18:33:02

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

Итак. Символьные дисплеи на контроллере 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 KiB) Скачиваний: 36
Последний раз редактировалось Demiurg Ср окт 26, 2022 19:02:40, всего редактировалось 1 раз.

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

Ср окт 26, 2022 19:01:13

весь цикл занимает 84 мс.

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