AVR单片机C语言开发入门指南
本指南将分为以下几个部分,循序渐进地介绍:

- 第一章:认识你的伙伴——AVR单片机
- 第二章:开发环境搭建
- 第三章:第一个程序:点亮LED (Hello World!)
- 第四章:核心概念详解
- 第五章:进阶与资源
- 常见问题与建议
第一章:认识你的伙伴——AVR单片机
1 什么是AVR单片机?
AVR是由Atmel(现已被Microchip收购)公司开发的、基于增强型RISC架构的8位单片机,它以其高性能、低功耗、精简指令集和易于使用的开发工具而闻名,是全球电子爱好者、学生和工程师入门嵌入式系统的首选之一。
2 为什么选择AVR?
- 文档丰富:官方数据手册写得非常清晰,是学习的最佳资料。
- 社区庞大:网上有海量的教程、开源项目和代码示例,遇到问题很容易找到解决方案。
- 工具链成熟:
avr-gcc编译器、avrdude烧录工具等免费且功能强大。 - 易于上手:寄存器操作直观,对于理解底层硬件工作原理非常有帮助。
3 经典型号推荐
- ATmega328P:Arduino Uno的核心,资料最多,最适合入门。
- ATmega32:资源更丰富,引脚更多,适合做更复杂的项目。
- ATtiny85:小巧、便宜,适合制作小型项目,如LED控制、传感器读取等。
第二章:开发环境搭建
我们需要三样东西:硬件、软件和连接它们的桥梁。
1 硬件准备
- AVR单片机开发板:推荐购买一块现成的开发板,如 Arduino Uno (核心是ATmega328P) 或 ATmega32 开发板,这能帮你省去焊接电源、晶振、下载电路的麻烦。
- USB数据线:用于给开发板供电和程序下载。
- 杜邦线:用于连接外设(如LED、按键、传感器)。
- LED、电阻(220Ω-1kΩ)、按键:最基本的实验元件。
2 软件准备
我们将使用纯C语言 + Makefile 的方式进行开发,这比Arduino IDE更能让你理解底层原理。
-
文本编辑器:
(图片来源网络,侵删)- VS Code (强烈推荐):功能强大,插件丰富,对C语言支持极佳。
- Sublime Text / Notepad++:轻量级,也很好用。
-
工具链:我们将安装
avr-gcc工具集,它包含了编译器、链接器等。 -
烧录/下载工具:
avrdude通常会和工具链一起安装,它的作用是把编译好的程序文件写入单片机的Flash存储器。
3 环境验证
安装完成后,打开终端(Windows下是CMD或PowerShell,或MSYS2的终端),输入以下命令,如果能看到版本信息,说明安装成功。
avr-gcc --version avrdude -v
第三章:第一个程序:点亮LED
这是嵌入式开发的“Hello World!”,我们将让开发板上的一个LED灯闪烁。

1 硬件连接
- Arduino Uno: 板载的
LLED已经连接到了PB5引脚(ATmega328P的5号引脚),无需额外连接。 - 其他开发板: 将LED的负极(短脚)通过一个220Ω电阻连接到GND(地),正极(长脚)连接到一个GPIO引脚(例如PD0)。
2 编写代码
创建一个项目文件夹,avr_led_blink,在里面创建一个名为 main.c 的文件,内容如下:
// main.c
#include <avr/io.h> // 包含AVR寄存器定义的头文件
#include <util/delay.h> // 包含延时函数的头文件
int main(void) {
// 1. 设置PB5引脚为输出模式
// DDRB 是Data Direction Register B (端口B的数据方向寄存器)
// 将DDRB的第5位(DDB5)设置为1,表示PB5为输出
DDRB |= (1 << PB5);
// 2. 主循环,程序会一直在这里运行
while (1) {
// 3. 点亮LED: 给PB5引脚输出低电平 (Arduino的LED是低电平点亮)
PORTB &= ~(1 << PB5);
// 4. 延时500毫秒
_delay_ms(500);
// 5. 熄灭LED: 给PB5引脚输出高电平
PORTB |= (1 << PB5);
// 6. 延时500毫秒
_delay_ms(500);
}
return 0; // 理论上不会执行到这里
}
3 编译与烧录
直接在命令行编译比较繁琐,我们使用 Makefile 来自动化这个过程。
在 avr_led_blink 文件夹下,创建一个名为 Makefile 的文件(注意没有后缀名),内容如下:
# Makefile for AVR LED Blink
# 定义变量
MCU = atmega328p
F_CPU = 16000000UL # 16MHz晶振频率,根据你的开发板修改
TARGET = main
OBJECTS = main.o
PROGRAMMER = arduino # 使用Arduino作为烧录器,也可以是usbasp等
# 编译器选项
CFLAGS = -Os -DF_CPU=$(F_CPU) -mmcu=$(MCU) -Wall -Wextra
# 默认目标
all: $(TARGET).hex
# 将目标文件链接成elf文件
$(TARGET).elf: $(OBJECTS)
avr-gcc $(CFLAGS) -o $@ $^
# 将elf文件转换成hex文件(烧录格式)
$(TARGET).hex: $(TARGET).elf
avr-objcopy -O ihex -R .eeprom $< $@
# 烧录程序到单片机
flash: $(TARGET).hex
avrdude -p $(MCU) -P /dev/ttyACM0 -c $(PROGRAMMER) -b 115200 -U flash:w:$<
# 清理生成的文件
clean:
rm -f $(OBJECTS) $(TARGET).elf $(TARGET).hex
# .o文件的规则
%.o: %.c
avr-gcc $(CFLAGS) -c $< -o $@
重要提示:
- 修改
MCU和F_CPU以匹配你的单片机和晶振频率。 - 修改
PROGRAMMER和烧录命令中的-P参数(串口设备名),在Linux/macOS下通常是/dev/ttyACM0或/dev/ttyUSB0,在Windows下是COM3(需用双引号括起来,如-P "COM3")。
4 执行命令
在终端中,进入你的项目文件夹,然后执行:
# 1. 编译 make all # 2. 烧录 make flash
如果一切顺利,你会看到LED开始闪烁!恭喜你,你成功完成了第一个AVR C语言项目!
第四章:核心概念详解
1 端口与寄存器
AVR单片机的I/O(输入/输出)操作是通过操作一系列的特殊功能寄存器来完成的,以ATmega328P为例,它有3个8位的I/O端口:PORTA, PORTB, PORTC, PORTD。
每个端口都有三个关键的寄存器:
- DDRx (Data Direction Register):数据方向寄存器。
- 写
1:将对应引脚设置为输出。 - 写
0:将对应引脚设置为输入。
- 写
- PORTx:端口数据寄存器。
- 如果引脚是输出模式,写入
1输出高电平,写入0输出低电平。 - 如果引脚是输入模式,写入
1启用内部上拉电阻,写入0不启用上拉。
- 如果引脚是输出模式,写入
- PINx:端口输入寄存器。
- 用于读取引脚上的实际电平(无论输入还是输出模式都可以读)。
操作技巧:
- 不改变其他位:修改某个引脚时,使用位操作符 (置位),
&=(清位),^=(取反),避免影响同一寄存器中的其他引脚。DDRB |= (1 << PB5);// 只设置PB5为输出,不影响其他位。PORTB &= ~(1 << PB5);// 只清除PB5的输出位,不影响其他位。
2 位操作
这是AVR C的精髓。<avr/sfr_defs.h> (通常由 <avr/io.h> 包含) 提供了方便的宏定义:
bit_is_set(reg, bit):检查reg的bit位是否为1。bit_is_clear(reg, bit):检查reg的bit位是否为0。sbi(reg, bit):将reg的bit位置1 (Set Bit)。cbi(reg, bit):将reg的bit位清0 (Clear Bit)。
sbi(PORTB, PB5); 等同于 PORTB |= (1 << PB5);。
3 中断
中断是单片机处理外部事件(如按键按下、定时器溢出)的强大机制,当事件发生时,CPU会暂停当前任务,去执行一个预先写好的中断服务程序,执行完后再返回原来的任务。
- 使能全局中断:
sei();(Set Global Interrupt)。 - 禁止全局中断:
cli();(Clear Global Interrupt)。 - 配置特定中断:通过设置相应的中断屏蔽寄存器(如
EIMSK用于外部中断)和标志位。
4 定时器/计数器
定时器是单片机的核心外设之一,用于精确定时、产生PWM波、事件计数等。
- 工作模式:正常模式、CTC模式、PWM模式等。
- 预分频器:将外部时钟频率进行分频,以获得更长的定时范围。
- 比较匹配:在CTC模式下,当计数器值达到比较寄存器的值时,可以触发中断或改变引脚电平。
第五章:进阶与资源
1 如何学习?
- 精读数据手册:这是最重要的参考资料,学会查阅Datasheet和Application Notes。
- 阅读官方库:
avr-libc是官方提供的C语言库,里面有很多有用的函数和宏定义,pin_mode(),digital_write()的底层实现。 - 模仿与修改:从网上找开源项目,尝试理解代码,然后修改功能,这是最快的学习方式。
2 推荐资源
- 书籍:
- 《C和指针》 - 打好C语言基础。
- 《AVR编程与应用》 - 中文经典入门书籍。
- 《Making Embedded Systems》 - 思维方式的启发。
- 网站/社区:
- AVR Freaks Forum: 官方技术论坛。
- GitHub: 搜索 "avr project"。
- All About Circuits: 有很好的AVR教程系列。
- 视频:
- YouTube: 搜索 "AVR Tutorial"、"Embedded Systems"。
常见问题与建议
-
Q: 程序烧录后没有反应?
- A: 1. 检查Makefile中的
MCU、F_CPU、PROGRAMMER和串口号是否正确,2. 检查硬件连接(电源、晶振、复位电路),3. 尝试先拔再插USB线,或者重启电脑。
- A: 1. 检查Makefile中的
-
Q:
_delay_ms()不工作?- A:
_delay_ms()依赖于F_CPU的定义,确保你在Makefile中正确设置了F_CPU,并且在编译时通过-DF_CPU选项传递给了编译器。
- A:
-
Q: 学习Arduino和直接学AVR C有什么区别?
- A: Arduino是一个优秀的原型开发平台,它封装了底层细节,让你能快速实现想法,直接学习AVR C能让你深入理解硬件,知道代码是如何与寄存器交互的,这对于进行底层优化、开发复杂系统或应对没有现成库的芯片至关重要。建议先学AVR C打好基础,再用Arduino加速开发。
希望这份指南能帮助你顺利开启AVR单片机的开发之旅!祝你玩得开心!
