Обновить

Комментарии 5

Начинал на советском программируемом калькуляторе ))

реклама услуг?

Каких?

  • За 2‑месяца изучил архитектуру 8051, PIC, AVR, купил несколько справочников и через 4 месяца собрал первый работающий проект (управление светодиодом).

вот очень бы хотелось реальных примеров всей цепочки промтов и полученого кода и желательно посложнее мигания светодиодами. хотя мигать светодиодом можно по разному

Вот пример работы модели qwen3-coder-next:q8_0, размер модели 84 Гб.

Запрос

Напиши программу для вывода текста на LCD дисплей 20х4 строк подключенный к микроконтроллеру ATMEGA8 по 4х проводной схеме. Периферия контроллера инициализирована в IDE ICCAVR (Image Craft). Частота генератора 14.7456МГц.

Ответ

Вот пример программы для управления LCD-дисплеем 20×4 (20 символов × 4 строки) по 4-проводному интерфейсу, подключённому к микроконтроллеру ATmega8, с использованием компилятора ICCAVR (ImageCraft). Частота тактирования — 14.7456 МГц.

🔧 Предположения по подключению (стандартная 4-проводная схема):
RS (Register Select) → PD2
E (Enable) → PD3
D4 → PD4
D5 → PD5
D6 → PD6
D7 → PD7
RW → GND (или подключить к PD1 и установить в 0)
Питание и контраст — как обычно (VDD, GND, V0 через потенциометр)
✅ Дополнительно: можно использовать #include и задержки через delay_us() / delay_ms(), либо настроить таймер. В ICCAVR встроена поддержка delay_us() при указании частоты в проекте (14.7456 МГц).

Текст программы

#include <iom8v.h>
#include <macros.h>
#include <stdlib.h>
#include <string.h>

// Настройка подключения LCD (4-битный режим)
#define RS_PIN   2  // PD2
#define E_PIN    3  // PD3
#define D4_PIN   4  // PD4
#define D5_PIN   5  // PD5
#define D6_PIN   6  // PD6
#define D7_PIN   7  // PD7

#define LCD_PORT_DIR  DDRD
#define LCD_PORT_OUT  PORTD

// Макросы для управления линиями
#define RS_HIGH()   (LCD_PORT_OUT |= (1 << RS_PIN))
#define RS_LOW()    (LCD_PORT_OUT &= ~(1 << RS_PIN))
#define E_HIGH()    (LCD_PORT_OUT |= (1 << E_PIN))
#define E_LOW()     (LCD_PORT_OUT &= ~(1 << E_PIN))

// Прототипы функций
void lcd_init(void);
void lcd_command(unsigned char cmd);
void lcd_data(unsigned char data);
void lcd_clear(void);
void lcd_home(void);
void lcd_puts(const char *s);
void lcd_gotoxy(unsigned char x, unsigned char y);

// Задержка в микросекундах (предполагается, что F_CPU = 14745600UL)
// В ICCAVR можно использовать delay_us() из <delay.h>, но для портативности сделаем свою
void delay_us(unsigned int us) {
    unsigned int i;
    // При 14.7456 МГц ~1 цикл ≈ 0.068 мкс → 14.7456 МГц / 4 = 3.6864 МГц тактов (если делитель 4),
    // но упростим: в ICCAVR delay_us() реализован через циклы
    // Лучше использовать _delay_us() из <util/delay.h>, если доступно
    // Но в ICCAVR можно включить built-in delay:
    // ВICC: #include <intrinsics.h> и использовать __delay_cycles()
    // Или используем простую имитацию:
    for (i = 0; i < us * 14; i++) { // Примерная настройка под 14.7456 МГц
        asm("nop");
    }
}

void delay_ms(unsigned int ms) {
    unsigned int i;
    for (i = 0; i < ms; i++) {
        delay_us(1000);
    }
}

// Передача байта в LCD (только старший или младший полубайт)
// mode: 0 = команда, 1 = данные
void lcd_write_nibble(unsigned char nibble, unsigned char mode) {
    // Очищаем биты D4-D7
    LCD_PORT_OUT &= ~((1 << D4_PIN) | (1 << D5_PIN) | (1 << D6_PIN) | (1 << D7_PIN));

    // Устанавливаем биты D4-D7
    if (nibble & 0x01) LCD_PORT_OUT |= (1 << D4_PIN);
    if (nibble & 0x02) LCD_PORT_OUT |= (1 << D5_PIN);
    if (nibble & 0x04) LCD_PORT_OUT |= (1 << D6_PIN);
    if (nibble & 0x08) LCD_PORT_OUT |= (1 << D7_PIN);

    if (mode) RS_HIGH();
    else      RS_LOW();

    E_HIGH();
    delay_us(1); // E-импульс ≥ 450 нс → 1 мкс безопасно
    E_LOW();
}

// Отправка полного байта (2 такта по 4 бита)
void lcd_write_byte(unsigned char byte, unsigned char mode) {
    // Старший полубайт
    lcd_write_nibble((byte >> 4) & 0x0F, mode);
    // Младший полубайт
    lcd_write_nibble(byte & 0x0F, mode);
}

// Инициализация LCD 20x4 (HD44780, 4-бит, 2 строки, 5x8 символов)
void lcd_init(void) {
    // Настройка порта D как выход (как минимум RS, E, D4-D7)
    LCD_PORT_DIR |= (1 << RS_PIN) | (1 << E_PIN) |
                    (1 << D4_PIN) | (1 << D5_PIN) | (1 << D6_PIN) | (1 << D7_PIN);
    LCD_PORT_OUT &= ~((1 << RS_PIN) | (1 << E_PIN)); // RS=0, E=0

    delay_ms(20); // Ждём стабилизации напряжения

    // 1. Первая инициализация: передача 0x03 (3 раза) — обязательная последовательность
    RS_LOW();
    E_LOW();
    // Отправляем 0x03 как старший полубайт (младший — 0)
    LCD_PORT_OUT &= ~((1 << D4_PIN) | (1 << D5_PIN) | (1 << D6_PIN) | (1 << D7_PIN));
    LCD_PORT_OUT |= (1 << D6_PIN) | (1 << D7_PIN); // 0x03 = 0000 0011 → D6,D7=1

    E_HIGH(); delay_us(1); E_LOW();
    delay_ms(5);

    // Повтор 0x03
    E_HIGH(); delay_us(1); E_LOW();
    delay_us(150);

    // Повтор 0x03
    E_HIGH(); delay_us(1); E_LOW();
    delay_ms(5);

    // Теперь переводим в 4-битный режим: отправляем 0x02 (function set: 4-bit)
    RS_LOW();
    LCD_PORT_OUT &= ~((1 << D4_PIN) | (1 << D5_PIN) | (1 << D6_PIN) | (1 << D7_PIN));
    LCD_PORT_OUT |= (1 << D5_PIN); // 0x02 = 0000 0010

    E_HIGH(); delay_us(1); E_LOW();
    delay_ms(5);

    // Теперь пошлём функциональные команды через lcd_write_byte()
    // Function Set: 4-bit, 2 строки, 5x8 dots → 0x28
    lcd_write_byte(0x28, 0);
    delay_ms(5);

    // Display ON/OFF Control: дисплей вкл, курсор выкл, мигание выкл → 0x0C
    lcd_write_byte(0x0C, 0);
    delay_ms(5);

    // Clear Display → 0x01
    lcd_write_byte(0x01, 0);
    delay_ms(5); // clear takes 1.64 ms

    // Entry Mode Set: инкремент, сдвиг выкл → 0x06
    lcd_write_byte(0x06, 0);
    delay_us(50);
}

// Отправка команды
void lcd_command(unsigned char cmd) {
    lcd_write_byte(cmd, 0);
    // Некоторые команды требуют задержки:
    if (cmd == 0x01 || cmd == 0x02) delay_ms(2); // clear/home ~1.64 мс
    else delay_us(100);
}

// Отправка данных
void lcd_data(unsigned char data) {
    lcd_write_byte(data, 1);
    delay_us(50);
}

// Очистка дисплея
void lcd_clear(void) {
    lcd_command(0x01);
    delay_ms(2);
}

// Возврат в начало
void lcd_home(void) {
    lcd_command(0x02);
    delay_ms(2);
}

// Вывод строки
void lcd_puts(const char *s) {
    while (*s) {
        lcd_data(*s++);
    }
}

// Установка курсора: x = 0..19, y = 0..3
void lcd_gotoxy(unsigned char x, unsigned char y) {
    unsigned char ddram_addr;
    // Адреса строк для HD44780 (стандартный):
    // 0: 0x00
    // 1: 0x40
    // 2: 0x14
    // 3: 0x54
    const unsigned char line_offsets[4] = {0x00, 0x40, 0x14, 0x54};

    if (y > 3) y = 3;
    if (x > 19) x = 19;

    ddram_addr = line_offsets[y] + x;
    lcd_command(0x80 | ddram_addr); // Set DDRAM address
}

// === ГЛАВНАЯ ФУНКЦИЯ ===
void main(void) {
    // Инициализация
    lcd_init();

    // Пример вывода
    lcd_gotoxy(0, 0);
    lcd_puts("Hello, World!");
    lcd_gotoxy(0, 1);
    lcd_puts("LCD 20x4 Test");
    lcd_gotoxy(0, 2);
    lcd_puts("Freq: 14.7456MHz");
    lcd_gotoxy(0, 3);
    lcd_puts("ICC + ATmega8");

    // Бесконечный цикл
    while (1) {
        // Можно добавить мигание или обновление
        delay_ms(1000);
    }
}

Ответ занял 1 секунду

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации