须知
频率为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;
}
}
}