频率为4M

跑马灯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#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动画函数
}


数码管显示时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#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毫秒
}
}

按键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#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(); // 按键处理
}

显示电压值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#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;
}
}
}