You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写AVR的C语言定时器程序实现LCD显示定时器及指定图示内容

Hey there! Let's build this AVR timer project with LCD display—covering both the timer info output and that custom graphic line-by-line display. I'll use the ATmega328P (super common for AVR projects) and a standard HD44780-compatible 16x2 LCD, writing pure C for AVR-GCC.

AVR Timer & LCD Display Implementation

Prerequisites

  • ATmega328P (or similar 8-bit AVR)
  • HD44780 16x2 LCD module
  • AVR-GCC compiler & avrdude for flashing
  • 16MHz crystal oscillator (or use internal 8MHz with prescaling)
  • Breadboard & jumper wires

1. Hardware Connections

Let's map the pins first (you can adjust these to your setup):

  • LCD RS → PD0
  • LCD EN → PD1
  • LCD D4 → PD2
  • LCD D5 → PD3
  • LCD D6 → PD4
  • LCD D7 → PD5
  • Timer1 uses its default pins (we'll use interrupts, no hardware output needed)

2. Code Implementation

Here's the full code with detailed comments, covering both required functions:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>

// LCD Pin Definitions
#define LCD_RS PD0
#define LCD_EN PD1
#define LCD_D4 PD2
#define LCD_D5 PD3
#define LCD_D6 PD4
#define LCD_D7 PD5

// Timer Variables
volatile uint8_t seconds = 0;
volatile uint8_t minutes = 0;
volatile uint8_t hours = 0;

// Custom graphic data (matches the requested rounded square graphic, split into 8 lines)
uint8_t custom_graphic[8] = {
    0b00000,
    0b01110,
    0b10001,
    0b10001,
    0b11111,
    0b10001,
    0b10001,
    0b01110
};

// LCD Helper Functions
void lcd_send_command(uint8_t cmd) {
    // Send upper nibble
    PORTD = (PORTD & 0x0F) | (cmd & 0xF0);
    PORTD &= ~(1 << LCD_RS);
    PORTD |= (1 << LCD_EN);
    _delay_us(1);
    PORTD &= ~(1 << LCD_EN);
    _delay_us(200);
    
    // Send lower nibble
    PORTD = (PORTD & 0x0F) | ((cmd << 4) & 0xF0);
    PORTD |= (1 << LCD_EN);
    _delay_us(1);
    PORTD &= ~(1 << LCD_EN);
    _delay_ms(2);
}

void lcd_send_data(uint8_t data) {
    // Send upper nibble
    PORTD = (PORTD & 0x0F) | (data & 0xF0);
    PORTD |= (1 << LCD_RS);
    PORTD |= (1 << LCD_EN);
    _delay_us(1);
    PORTD &= ~(1 << LCD_EN);
    _delay_us(200);
    
    // Send lower nibble
    PORTD = (PORTD & 0x0F) | ((data << 4) & 0xF0);
    PORTD |= (1 << LCD_EN);
    _delay_us(1);
    PORTD &= ~(1 << LCD_EN);
    _delay_ms(2);
}

void lcd_init() {
    DDRD |= (1 << LCD_RS) | (1 << LCD_EN) | (1 << LCD_D4) | (1 << LCD_D5) | (1 << LCD_D6) | (1 << LCD_D7);
    _delay_ms(20);
    
    lcd_send_command(0x02); // Switch to 4-bit mode
    lcd_send_command(0x28); // 2 lines, 5x8 font
    lcd_send_command(0x0C); // Display on, cursor off
    lcd_send_command(0x06); // Auto-increment cursor
    lcd_send_command(0x01); // Clear display
    _delay_ms(2);
}

void lcd_set_cursor(uint8_t row, uint8_t col) {
    uint8_t address;
    if(row == 0) address = 0x80 + col;
    else address = 0xC0 + col;
    lcd_send_command(address);
}

void lcd_print_string(char *str) {
    while(*str != '\0') {
        lcd_send_data(*str);
        str++;
    }
}

// Load custom character into LCD CGRAM
void lcd_load_custom_char(uint8_t location, uint8_t *char_data) {
    location &= 0x07; // Only 8 custom chars allowed (0-7)
    lcd_send_command(0x40 + (location * 8));
    for(uint8_t i=0; i<8; i++) {
        lcd_send_data(char_data[i]);
    }
}

// Timer1 Initialization (CTC mode, 1 second interrupt)
void timer1_init() {
    TCCR1B |= (1 << WGM12); // Enable CTC mode
    OCR1A = 15624; // For 16MHz clock, 1024 prescaler: (16e6 / 1024) - 1 = 15624
    TIMSK1 |= (1 << OCIE1A); // Enable compare match interrupt
    TCCR1B |= (1 << CS12) | (1 << CS10); // Set 1024 prescaler
    sei(); // Enable global interrupts
}

// Timer1 Compare Match Interrupt (updates time variables)
ISR(TIMER1_COMPA_vect) {
    seconds++;
    if(seconds == 60) {
        seconds = 0;
        minutes++;
        if(minutes == 60) {
            minutes = 0;
            hours++;
            if(hours == 24) hours = 0;
        }
    }
}

// Function to display timer info on LCD
void display_timer_info() {
    char time_str[16];
    lcd_set_cursor(0, 0);
    snprintf(time_str, sizeof(time_str), "Time: %02d:%02d:%02d", hours, minutes, seconds);
    lcd_print_string(time_str);
}

// Function to display custom graphic line by line
void display_graphic_line_by_line() {
    lcd_send_command(0x01); // Clear display
    _delay_ms(2);
    
    // Display each line of the graphic one by one with delay
    for(uint8_t i=0; i<8; i++) {
        uint8_t temp_char[8] = {0};
        temp_char[i] = custom_graphic[i]; // Only show the i-th line of the graphic
        lcd_load_custom_char(0, temp_char);
        
        lcd_set_cursor(0, 5); // Center the graphic on the LCD
        lcd_send_data(0); // Display the partial custom character
        _delay_ms(500); // Wait half a second between lines
    }
    
    // Show the full completed graphic for 2 seconds
    lcd_load_custom_char(0, custom_graphic);
    lcd_set_cursor(0, 5);
    lcd_send_data(0);
    _delay_ms(2000);
}

int main(void) {
    lcd_init();
    timer1_init();
    
    while(1) {
        // Toggle between timer info and graphic display every 5 seconds
        display_timer_info();
        _delay_ms(5000);
        display_graphic_line_by_line();
    }
}

3. Key Explanations

  • Timer Setup: We use Timer1 in CTC mode with a 1024 prescaler to trigger a 1-second interrupt, which updates our time variables (hours, minutes, seconds).
  • LCD Custom Characters: The requested graphic is split into 8 5-bit lines (matching the LCD's 5x8 font grid). We load each line sequentially to build the graphic step-by-step.
  • Display Toggle: The main loop switches between showing the timer info and the animated graphic every 5 seconds—you can adjust this delay or add a button for manual switching if needed.

4. Troubleshooting Tips

  • Timer runs too fast/slow: Adjust the OCR1A value based on your AVR's clock speed. For an 8MHz clock, use OCR1A = 7811 with a 1024 prescaler.
  • LCD not displaying anything: Double-check pin connections, ensure 4-bit mode is configured correctly, and adjust the LCD contrast potentiometer.
  • Graphic lines are incorrect: Tweak the custom_graphic array values to match the exact pixels of your target graphic.

内容的提问来源于stack exchange,提问作者Kimo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:13:36