Комментарии 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 секунду

Как стать программистом: от Intel 286 до Large Language Models