三峡大学(CTGU)单片机课设代码

本文介绍了使用Mega16H开发板实现的跑马灯LED动画、数码管时间显示以及按键控制功能,同时包括电压值的实时采集。通过定时器和中断管理,实现了动态时间和电压数据的实时更新。
摘要由CSDN通过智能技术生成

须知

频率为4M

跑马灯

#include <mega16.h>
#include <delay.h>

// 控制LED动画的函数
void led()
{
    char i = 0, j = (i + 6) % 7 + 1; // 初始化LED位置的变量
    PORTB = 0xFF; // 将所有PORTB引脚设为高电平(LED初始关闭状态)
    DDRB = 0xFF;  // 将所有PORTB引脚设为输出,用于连接LED
    while(1){
        // 切换在位置i和j的LED状态(二进制取反)
        PORTB = ~(1 << i) & ~(1 << j);
        delay_ms(100); // 延时100毫秒
        if(++i > 7) i = 0; // 如果i超过7,则将i加1并重置为0
        if(++j > 7) j = 0; // 如果j超过7,则将j加1并重置为0
    }
}

void main()
{
    led(); // 调用LED动画函数
}


数码管显示时间

#include <delay.h>
#include <mega16.h>

flash char led_7[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
flash char position[4] = {0b00000000, 0b01000000, 0b00100000, 0b00010000};

char time[2];       // 时、分、秒计数
char dis_buff[4];  // 显示缓冲区,存放要显示的 6 个字符的段码值
char time_counter; // 1 秒计数器
bit point_on;       // 秒显示标志

void display(void) // 扫描显示函数,执行时间 12ms
{
    char i;
    for(i = 0;i < 4;i ++){
        PORTC = led_7[dis_buff[i]];
        if(i == 0){
            PORTA.6 = 1;
            PORTD = 0; 
        }else{
            PORTD = position[i];
            PORTA.6 = 0; 
        }
        delay_ms(2);  
        PORTC = 0xFF;
        PORTD = 0; 
    }
    
}

void time_to_disbuffer(void) // 时间值送显示缓冲区函数
{
    char i, j = 0;
    for (i = 0; i < 2; i++)
    {
        dis_buff[j++] = time[i] % 10;
        dis_buff[j++] = time[i] / 10;
    }
}


void main(void)
{
    PORTC = 0xFF; 
    DDRC = 0xFF;
    
    PORTD = 0; 
    PORTA.6 = 0;
    DDRD =  0b01110000; 
    DDRA.6 = 1;
    time[1] = 15;   // 初始化秒数
    time[0] = 51;   // 初始化分钟数
    time_to_disbuffer();  // 初始化显示缓冲区

    while (1)
    {
        display(); // 调用显示函数
        if (++time_counter >= 40)
        {
            time_counter = 0;      // 重置计数器
            point_on = ~point_on;  // 切换秒显示标志
            if (++time[0] >= 60)
            {
                time[0] = 0;
                if (++time[1] >= 60)
                {
                    time[1] = 0;  // 重置分钟数
                }
            }
            time_to_disbuffer();  // 将时间值送显示缓冲区
        }
        delay_ms(13); // 延时13毫秒
    }
}

按键

#include <mega16.h>
#include <stdint.h>

#define uchar unsigned char
#define uint  unsigned int

#define LED  PORTB0
#define LED0 PORTB1
#define LED1 PORTD4
#define LED2 PORTD5
#define LED3 PORTD6
#define LED4 PORTA6
#define Dataport PORTC

#define LED_Data  PORTB

#define S1 PIOD2
#define S2 PIOD0
#define S3 PIOD3
#define S4 PIOD1
#define S5 PIOA7


uchar keyValue;
bit point_on = 0;

flash char led_7[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};

void delay(uint time)
{
    uint i, j;
    for (i = 0; i < time; i++)
    {
        for (j = 0; j < 30; j++);
    }
}

void IO_init(void)
{
    DDRB = 0xFF;
    PORTB = 0xFF;
    DDRD = 0x00;
    PORTD = 0xFF;
    DDRA = 0xFF;
    PORTA = 0xFF;
    DDRC = 0xFF;
    PORTC = 0x00;
}

void led_init(){
   PORTD.4=0;
   PORTD.5=0;
   PORTD.6=0;
   PORTA.6=0;
}

void keyScan()
{
    uchar x, y;

    // 设置PORTD的低2位为输出,高2位为输入
    DDRD = 0x03;
    // 设置PORTD的高2位为高电平,作为输入的上拉电阻
    PORTD = 0x0C;

    // 检查是否有按键被按下(高2位不为高电平)
    if ((PIND & 0x0C) != 0x0C)
    {
        // 引入延迟以去抖动按键
        delay(20);

        // 再次检查是否有按键被按下
        if ((PIND & 0x0C) != 0x0C)
        {
            // 读取PIND的高2位状态(x)
            x = (PIND & 0x0C);
            // 将DDRD的高2位更改为输出
            DDRD = 0x0C;
            // 将PORTD的高2位更改为输入
            PORTD = 0x03;
            // 再次引入延迟
            delay(5);
            // 读取PIND的低2位状态(y)
            y = (PIND & 0x03);
            // 将x和y组合以获取按下的按键值
            keyValue = x | y;

            // 等待按键释放
            while ((PIND & 0x03) != 0x03);
        }
    }
}

void keyHandle()
{
    switch(keyValue)
    {
        case 0x06:
        {
            PORTB = 0xfe;
            led_init();
            PORTD.4 = 1;
            break;
        }
        case 0x0a:
        {
            PORTB = 0xfd;
            led_init();
            PORTD.5 = 1;
            break;
        }
        case 0x05:
        {
            PORTB = 0xfb;
            led_init();
            PORTD.6 = 1;
            break;
        }
        case 0x09:
        {
            PORTB = 0xf7;
            led_init();
            PORTA.6 = 1;
            break;
        }
        default:
            break;
    }
}

void timer0_init()
{   
    TCCR0 |= (1 << WGM01); // 设置为CTC模式
    OCR0 = 125; // 比较匹配值,使得定时器溢出时间为5000us
    TIMSK |= (1 << OCIE0); // 启用定时器0中断
    TCCR0 |= (1 << CS02); // 设置分频器为256,启动定时器
}

void main()
{
    uint8_t i = 0;
    IO_init();
    led_init();
    timer0_init();
    #asm("sei") // 允许全局中断

    
    while (1)
    {   
        // 根据标志位控制数码管点亮
        if(point_on)PORTC = led_7[i] | 0x80;
        else PORTC = led_7[i];


        keyScan();
        keyHandle();

        if(++ i >= 10) i = 0;

        delay(5000);
    }
}

interrupt [TIM0_COMP] void timer0_ISR(void)
{
    keyScan(); // 按键扫描
    keyHandle(); // 按键处理
}

显示电压值

#include <mega16.h>
#include <delay.h>

flash char led_7[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
flash char position[4] = {0b00000000, 0b01000000, 0b00100000, 0b00010000};

unsigned char dis_buff[4] = {0, 0, 0, 0};
bit time_2ms_ok;

// ADC 电压值送显示缓冲区函数
void adc_to_disbuffer(unsigned int adc)             
{
    char i;
    for (i = 0; i <= 3; i++)
    {
        dis_buff[i] = adc % 10;
        adc /= 10;
    }
}

void display(void) 
{
    char i;
    for(i = 0;i < 4;i ++){
        PORTC = led_7[dis_buff[i]];
        if(i == 0){
            PORTA.6 = 1;
            PORTD = 0; 
        }else{
            PORTD = position[i];
            PORTA.6 = 0; 
        }
        delay_ms(2);  
        PORTC = 0xFF;
        PORTD = 0; 
    }
}

// Timer 0 比较匹配中断服务
interrupt[TIM0_COMP] void timer0_comp_isr(void)
{
    time_2ms_ok = 1;
}

// ADC 转换完成中断服务
interrupt[ADC_INT] void adc_isr(void)
{
    unsigned int adc_data, adc_v;
    adc_data = ADCW;                               // 读取 ADC 置换结果
    adc_v = (unsigned long)adc_data * 5000 / 1024; // 换算成电压值
    adc_to_disbuffer(adc_v);
}

void main(void)
{
    PORTC = 0xFF; 
    DDRC = 0xFF;
    
    PORTD = 0; 
    PORTA.6 = 0;
    DDRD =  0b01110000; 
    DDRA.6 = 1;   
    
    // T/C0 初始化
    TCCR0 = 0x0B; // 内部时钟,64 分频(4M/64=62.5KHz),CTC 模式
    TCNT0 = 0x00;
    OCR0 = 0x7C;  // OCR0 = 0x7C(124),(124+1)/62.5=2ms
    TIMSK = 0x02; // 允许 T/C0 比较中断

    // ADC 初始化
    ADMUX = 0x40; // 参考电源 AVcc、ADC0 单端输入
    SFIOR &= 0x1F;
    SFIOR |= 0x60; // 选择 T/C0 比较匹配中断为 ADC 触发源
    ADCSRA = 0xAD; // ADC 允许、自动触发转换、ADC 转换中断允许、ADCclk=125Kz

    #asm("sei") 

    while (1)
    {
        if (time_2ms_ok)
        {
            display(); // LED 扫描显示
            time_2ms_ok = 0;
        }
    }     
}

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值