PIC单片机C语言程序设计指南
PIC单片机是美国微芯公司生产的一种8位微控制器,以其高性价比、丰富的外设和强大的开发工具链而闻名,使用C语言进行PIC开发,可以大大提高开发效率,降低编程门槛,并增强代码的可移植性。

(图片来源网络,侵删)
开发环境搭建
在开始编程之前,你需要准备以下工具:
-
硬件:
- PIC单片机: PIC16F877A, PIC18F4550, PIC16F18326 等。
- 编程器/调试器: PICkit 3, PICkit 4, ICD 3, 或者集成在开发板上的USB转串口/调试模块。
- 目标板: 包含PIC单片机、电源、时钟电路、LED、按键等基本元件。
- 电脑: 运行Windows, macOS或Linux系统。
-
软件:
- 集成开发环境: MPLAB X IDE (免费,官方推荐),它是一个功能强大的跨平台IDE。
- 编译器: XC8 (免费版有代码大小限制,但足够学习使用)、XC16 (用于16位PIC)、XC32 (用于32位PIC),我们以最常用的 XC8 为例。
- 库/软件包: MCC (Microchip Code Configurator),这是一个图形化配置工具,可以自动生成外设初始化代码,极大简化开发。
安装步骤:

(图片来源网络,侵删)
- 从 Microchip官网 下载并安装 MPLAB X IDE。
- 在安装MPLAB X时,会提示你安装相应的编译器(如XC8)。
- MCC作为MPLAB X的一个插件,通常也会被一同安装或可以后期通过插件管理器安装。
C语言程序基本结构
一个标准的PIC C语言程序通常包含以下几个部分:
// 1. 包含头文件
// 包含编译器提供的标准库和特定芯片的头文件
#include <xc.h> // XC8编译器的核心头文件,包含特殊功能寄存器定义
#include <stdint.h> // 包含标准整数类型定义,如 uint8_t, uint16_t
// 2. 配置位设置
// 这部分代码告诉单片机如何配置其硬件特性(如时钟源、看门狗等)
// 在MPLAB X中,通常通过MCC图形化设置,它会自动生成这部分代码。
// 手动编写时,使用 #pragma config 指令。
#pragma config FOSC = HS // 振荡器选择为高速晶体振荡器
#pragma config WDTE = OFF // 关闭看门狗定时器
// 3. 全局变量和函数声明
// 在函数外部定义的变量,整个程序都可以访问
uint8_t counter = 0;
// 函数声明(如果函数定义在main之后)
void myFunction(void);
// 4. 主函数
// 程序的入口点,程序从这里开始执行
void main(void) {
// --- 初始化部分 ---
// 在这里设置I/O口、定时器、串口等外设
TRISB = 0x00; // 将PORTB的所有引脚设置为输出
LATB = 0x00; // 初始化PORTB输出为低电平
// --- 主循环 ---
while(1) { // 这是一个无限循环,单片机程序通常都在这里运行
// --- 用户代码 ---
LATB = ~LATB; // 将PORTB的输出电平取反,实现LED闪烁
__delay_ms(500); // 调用内部延时函数,延时500毫秒
// counter++;
// myFunction();
}
}
// 5. 其他函数定义
void myFunction(void) {
// 函数体
}
核心概念与实践
I/O端口控制
这是最基本也是最常用的操作,PIC的I/O端口通常由两个寄存器控制:
- TRISx (数据方向寄存器):
TRISx = 1: 将引脚设置为输入模式。TRISx = 0: 将引脚设置为输出模式。x代表端口字母,如TRISB,TRISC。
- LATx (锁存器寄存器):
LATx = 1: 向引脚输出高电平。LATx = 0: 向引脚输出低电平。- 重要提示:对于现代PIC单片机,推荐使用
LATx来设置输出电平,而不是PORTx。PORTx主要用于读取引脚状态,写入PORTx可能会引发“读-修改-写”问题。
示例:让连接在RB0引脚上的LED闪烁
#include <xc.h>
#include <stdint.h>
#pragma config FOSC = HS
#pragma config WDTE = OFF
void main(void) {
TRISBbits.TRISB0 = 0; // 将RB0设置为输出
// 或者 TRISB = 0b11111110; (将RB0设为输出,其他设为输入)
while(1) {
LATBbits.LATB0 = 1; // LED亮 (假设是共阴极)
__delay_ms(500);
LATBbits.LATB0 = 0; // LED灭
__delay_ms(500);
}
}
定时器与延时
延时函数 __delay_ms() 是XC8编译器提供的内置函数,非常方便。

(图片来源网络,侵删)
-
使用条件:必须在程序中定义
_XTAL_FREQ宏,告诉编译器你的系统时钟频率是多少。#define _XTAL_FREQ 4000000// 定义为4MHz
-
硬件定时器:
- 内置的定时器比软件延时更精确,且不会占用CPU资源。
- 通过配置定时器寄存器(如TMR0, TMR1, TMR2)来设置。
- 使用TMR0实现1秒定时,可以中断CPU去执行特定任务。
示例:使用TMR0实现LED闪烁
#include <xc.h>
#include <stdint.h>
#pragma config FOSC = HS
#pragma config WDTE = OFF
#define LED LATBbits.LATB0
volatile uint16_t overflow_count = 0;
// TMR0中断服务函数
void __interrupt() myISR(void) {
if (TMR0IF) { // 检查TMR0溢出标志
TMR0IF = 0; // 清除标志位
TMR0 = 256 - 250; // 重新加载初值,假设时钟为4MHz,分频为1:256
overflow_count++;
if (overflow_count >= 2000) { // 溢出2000次,大约1秒
overflow_count = 0;
LED = ~LED; // 切换LED状态
}
}
}
void main(void) {
TRISBbits.TRISB0 = 0; // LED引脚为输出
LED = 0; // 初始状态为灭
// TMR0配置
OPTION_REGbits.T0CS = 0; // 内部指令时钟
OPTION_REGbits.PSA = 0; // 分频器分配给TMR0
OPTION_REGbits.PS = 0b111; // 分频比为1:256
TMR0 = 256 - 250; // 设置初值
TMR0IE = 1; // 使能TMR0中断
GIE = 1; // 全局中断使能
while(1) {
// 主循环可以执行其他任务,定时由中断处理
}
}
中断
中断是单片机的核心机制之一,当特定事件发生时(如定时器溢出、引脚电平变化),CPU会暂停当前任务,去执行一个预先写好的“中断服务函数”,执行完毕后再返回原来的任务。
- 关键步骤:
- 配置中断源: 设置相应的中断使能位(如
TMR0IE,RBIE)。 - 编写中断服务函数: 使用
__interrupt()关键字定义。 - 全局中断使能: 设置
GIE = 1。 - 清除中断标志: 在ISR中,必须手动清除触发中断的标志位,否则会一直进入中断。
- 配置中断源: 设置相应的中断使能位(如
使用MCC进行外设配置(强烈推荐)
手动配置寄存器非常繁琐且容易出错,MCC可以让你通过图形化界面完成配置。
使用MCC配置UART(串口)的步骤:
- 在MPLAB X中,创建或打开一个项目。
- 点击菜单栏的 Tools -> Microchip Code Configurator (MCC)。
- 在左侧的 Component 列表中找到 USART,双击添加。
- 在右侧的配置界面中:
- 选择 Enable。
- 设置 Mode 为 Asynchronous。
- 设置 Baud Rate (9600)。
- 设置 TX and RX Pins。
- 点击 Generate 按钮,MCC会自动生成所有相关的初始化代码(
MCC.c和MCC.h)。 - 在你的
main.c文件中,只需包含MCC.h,然后调用SYSTEM_Initialize()函数即可完成所有配置。
示例:通过串口发送 "Hello World!"
#include "mcc.h" // 包含MCC生成的所有头文件和函数
void main(void) {
SYSTEM_Initialize(); // 初始化系统(包括UART)
printf("Hello World!\r\n"); // 使用标准库函数printf发送数据
while(1) {
// 主循环
}
}
注意: 使用 printf 需要在项目设置中启用标准库,并指定 stdout 为 UART,MCC通常会帮你配置好。
完整示例:LED闪烁与按键控制
目标:
- RB0连接一个LED,实现1秒闪烁。
- RB1连接一个按键,按下时改变LED的闪烁速度。
硬件连接:
- RB0 -> LED -> 电阻 -> GND
- RB1 -> 按键 -> VCC (上拉电阻)
代码:
#include <xc.h>
#include <stdint.h>
#pragma config FOSC = HS // 高速晶体
#pragma config WDTE = OFF // 关闭看门狗
#define _XTAL_FREQ 4000000 // 系统时钟4MHz
#define LED_PIN LATBbits.LATB0
#define BUTTON_PIN PORTBbits.RB1
#define BUTTON_TRIS TRISBbits.TRISB1
// 全局变量
uint8_t blink_speed = 500; // 默认闪烁速度500ms
void main(void) {
// 1. 初始化I/O
TRISB = 0b11111110; // RB0为输出,RB1为输入
LED_PIN = 0; // 初始LED为灭
// 2. 主循环
while(1) {
// 检测按键
if (BUTTON_PIN == 0) { // 假设按键按下为低电平
__delay_ms(20); // 消抖
if (BUTTON_PIN == 0) {
// 按键确实被按下
if (blink_speed == 500) {
blink_speed = 100; // 加快闪烁
} else {
blink_speed = 500; // 恢复正常速度
}
// 等待按键释放
while (BUTTON_PIN == 0);
__delay_ms(20); // 再次消抖
}
}
// 控制LED闪烁
LED_PIN = ~LED_PIN;
__delay_ms(blink_speed);
}
}
学习建议与资源
- 从官方开始: Microchip官网有最权威的数据手册、参考手册和应用笔记。数据手册是你的“圣经”,必须学会查阅。
- 善用MCC: 不要一开始就陷入复杂的寄存器配置,先用MCC把外设跑起来,理解其工作原理后,再去看MCC生成的代码,学习寄存器级的操作。
- 实践出真知: 买一块开发板,从点亮LED开始,逐步尝试按键、定时器、串口、LCD、ADC等实验。
- 社区与论坛: Microchip官方社区、Stack Overflow、国内的电子发烧友论坛等都是解决问题的好地方。
推荐资源:
- Microchip官网: www.microchip.com
- MPLAB X IDE 和 XC8 编译器下载: MPLAB X IDE 页面
- YouTube: 搜索 "PIC MCC tutorial" 或 "PIC16F877A tutorial",有大量视频教程。
- 书籍: 《PIC Microcontroller and Embedded Systems》 by Muhammad Ali Mazidi 是一本经典的入门书籍。
希望这份指南能帮助你顺利开启PIC单片机的C语言编程之旅!祝你学习愉快!
