打印
[PIC®/AVR®/dsPIC®产品]

PIC16系列通信接口(UART、I2C、SPI)

[复制链接]
532|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Puchou|  楼主 | 2025-1-22 07:09 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
PIC16系列通信接口(UART、I2C、SPI)



UART通信接口
UART简介
UART(Universal Asynchronous Receiver/Transmitter)是一种通用串行通信接口,用于实现两个设备之间的异步数据传输。PIC16系列单片机通常集成了一个或多个UART模块,可以用于与外部设备(如计算机、传感器、其他单片机等)进行数据交换。UART通信具有以下特点:

异步通信:发送和接收数据时不需要同步时钟信号。

全双工通信:可以同时发送和接收数据。

字符帧:数据以字符帧的形式传输,每个字符帧通常包含起始位、数据位、奇偶校验位(可选)和停止位。

波特率:通信速率,单位是bps(bits per second),可以通过配置寄存器来设置。

UART硬件结构
PIC16系列单片机的UART模块通常包括以下几个主要部件:

发送移位寄存器:用于将数据转换为串行格式并发送。

接收移位寄存器:用于将接收到的串行数据转换为并行格式。

发送缓冲器:用于存储待发送的数据。

接收缓冲器:用于存储接收到的数据。

波特率生成器:用于生成通信所需的时钟频率。

UART寄存器配置
在使用UART进行通信之前,需要对相关寄存器进行配置。以下是一些常见的UART寄存器及其功能:

TXSTA:发送状态和控制寄存器

TX9:选择9位或8位数据传输

TXEN:使能发送

SYNC:选择同步或异步模式

BRGH:选择波特率高或低速模式

TRMT:发送完成标志位

RCSTA:接收状态和控制寄存器

RX9:选择9位或8位数据接收

CREN:使能接收

SREN:使能同步模式下的接收

ADDEN:使能地址检测

BAUDCON:波特率控制寄存器

BRG16:选择16位或8位波特率生成器

WUE:唤醒功能使能

ABDEN:自动波特率检测使能

ABDOVF:自动波特率检测溢出标志位

BAUDCTL:高级波特率控制寄存器(某些PIC16系列单片机可能没有此寄存器)

SMP:采样位选择

ABDEN:自动波特率检测使能

BDDSMP:波特率检测采样位选择

TXREG:发送数据寄存器

RCREG:接收数据寄存器

UART波特率设置
波特率是UART通信中的重要参数,可以通过以下公式计算:




其中,F osc 是单片机的振荡器频率,SPBRG是波特率生成寄存器。例如,如果使用4MHz的振荡器频率,希望设置波特率为9600bps,可以通过以下步骤设置SPBRG:

将4MHz转换为Hz:4000000 Hz

代入公式计算SPBRG值:



UART初始化
在使用UART进行通信之前,需要进行初始化。以下是一个初始化UART的示例代码:


#include <xc.h>



// 定义波特率生成寄存器值

#define SPBRG_VAL 25



void UART_Init(void) {

    // 设置波特率

    SPBRG = SPBRG_VAL;



    // 配置发送状态和控制寄存器

    TXSTA = 0b00100100; // 高速模式,8位数据,使能发送

    TXSTAbits.TX9 = 0;  // 8位数据

    TXSTAbits.BRGH = 1; // 高速模式

    TXSTAbits.TXEN = 1; // 使能发送



    // 配置接收状态和控制寄存器

    RCSTA = 0b10010000; // 使能接收,8位数据

    RCSTAbits.SPEN = 1;  // 使能串行端口

    RCSTAbits.CREN = 1;  // 使能接收



    // 配置波特率控制寄存器

    BAUDCON = 0b00000000; // 使用8位波特率生成器

    BAUDCONbits.BRG16 = 0; // 8位波特率生成器

}



void UART_WriteChar(char data) {

    while (!TXIF); // 等待发送缓冲器为空

    TXREG = data;  // 发送数据

}



char UART_ReadChar(void) {

    while (!RCIF); // 等待接收缓冲器有数据

    return RCREG;  // 读取数据

}



void UART_WriteString(char *str) {

    while (*str) {

        UART_WriteChar(*str++);

    }

}



int main(void) {

    // 初始化UART

    UART_Init();



    // 发送字符串

    UART_WriteString("Hello, World!");



    while (1) {

        // 读取字符并回显

        char receivedChar = UART_ReadChar();

        UART_WriteChar(receivedChar);

    }



    return 0;

}



UART中断处理
UART可以配置中断,以便在数据发送或接收完成时触发特定的处理函数。以下是一个使用UART中断的示例代码:


#include <xc.h>

#include <interrupts.h>



// 定义波特率生成寄存器值

#define SPBRG_VAL 25



// 接收缓冲区

char receiveBuffer[100];

int bufferIndex = 0;



void __interrupt() UART_ISR(void) {

    if (RCIF) { // 接收中断

        char receivedChar = RCREG;

        receiveBuffer[bufferIndex++] = receivedChar;

        if (receivedChar == '\n' || bufferIndex >= 100) {

            receiveBuffer[bufferIndex] = '\0'; // 终止字符串

            bufferIndex = 0; // 重置缓冲区索引

            // 处理接收到的数据

            UART_WriteString(receiveBuffer);

        }

        RCIF = 0; // 清除接收中断标志

    }



    if (TXIF) { // 发送中断

        if (bufferIndex < 100 && receiveBuffer[bufferIndex] != '\0') {

            TXREG = receiveBuffer[bufferIndex++];

        } else {

            TXIF = 0; // 清除发送中断标志

        }

    }

}



void UART_Init(void) {

    // 设置波特率

    SPBRG = SPBRG_VAL;



    // 配置发送状态和控制寄存器

    TXSTA = 0b00100100; // 高速模式,8位数据,使能发送

    TXSTAbits.TX9 = 0;  // 8位数据

    TXSTAbits.BRGH = 1; // 高速模式

    TXSTAbits.TXEN = 1; // 使能发送



    // 配置接收状态和控制寄存器

    RCSTA = 0b10010000; // 使能接收,8位数据

    RCSTAbits.SPEN = 1;  // 使能串行端口

    RCSTAbits.CREN = 1;  // 使能接收



    // 配置波特率控制寄存器

    BAUDCON = 0b00000000; // 使用8位波特率生成器

    BAUDCONbits.BRG16 = 0; // 8位波特率生成器



    // 开启接收中断

    PIE1bits.RCIE = 1; // 使能接收中断

    PIE1bits.TXIE = 1; // 使能发送中断

    INTCONbits.PEIE = 1; // 使能外围中断

    INTCONbits.GIE = 1;  // 使能全局中断

}



void UART_WriteChar(char data) {

    while (!TXIF); // 等待发送缓冲器为空

    TXREG = data;  // 发送数据

}



char UART_ReadChar(void) {

    while (!RCIF); // 等待接收缓冲器有数据

    return RCREG;  // 读取数据

}



void UART_WriteString(char *str) {

    while (*str) {

        UART_WriteChar(*str++);

    }

}



int main(void) {

    // 初始化UART

    UART_Init();



    while (1) {

        // 主循环可以处理其他任务

    }



    return 0;

}




UART通信示例
以下是一个简单的UART通信示例,展示如何在PIC16单片机和PC之间传输数据。假设使用4MHz的振荡器频率,波特率为9600bps。

硬件连接:

PIC16的TX引脚连接到PC的RX引脚

PIC16的RX引脚连接到PC的TX引脚

使用合适的电平转换器(如MAX232)进行电平转换

软件配置:

使用 MPLAB X IDE 进行开发

配置项目为4MHz振荡器频率

编写上述初始化和中断处理代码

测试:

使用串口调试助手(如Putty、TeraTerm等)连接到PC的串口

在调试助手中发送字符串,例如“Hello, PIC16!”

观察PIC16单片机通过UART回显接收到的字符串

I2C通信接口
I2C简介
I2C(Inter-Integrated Circuit)是一种串行通信协议,用于在多个设备之间进行简单的双向数据传输。PIC16系列单片机通常集成了I2C模块,可以用于与外部传感器、存储器等设备进行通信。I2C通信具有以下特点:

两线通信:SCL(时钟线)和SDA(数据线)

主从模式:一个主设备可以与多个从设备通信

多主设备:多个主设备可以共享总线

地址识别:每个从设备都有一个唯一的7位或10位地址

I2C硬件结构
PIC16系列单片机的I2C模块通常包括以下几个主要部件:

SCL引脚:时钟线

SDA引脚:数据线

RC2/SDA和RC3/SCL:通常用于连接I2C总线

控制寄存器:用于配置I2C模块的工作模式和参数

I2C寄存器配置
在使用I2C进行通信之前,需要对相关寄存器进行配置。以下是一些常见的I2C寄存器及其功能:

SSPCON1:I2C控制寄存器1

CKP:时钟极性

SSPEN:使能I2C模块

SSPOV:溢出标志位

WCOL:写冲突标志位

SSP1CKP:时钟极性选择

SSP1EN:使能I2C模块

SSPCON2:I2C控制寄存器2

ACKEN:使能ACK生成

ACKSTAT:ACK状态

SEN:启动条件

RSEN:重复启动条件

PEN:停止条件

RCEN:使能接收

ACKDT:ACK数据位

SSPSTAT:I2C状态寄存器

BF:缓冲器满标志位

UA:未决地址标志位

RW:读写标志位

S:启动条件标志位

P:停止条件标志位

D:数据方向标志位

R:重复启动条件标志位

SSPADD:I2C地址寄存器

SSPBUF:I2C数据缓冲器

I2C初始化
在使用I2C进行通信之前,需要进行初始化。以下是一个初始化I2C的示例代码:


#include <xc.h>

#include <stdint.h>



// 定义I2C时钟频率

#define I2C_CLOCK 100000



// 计算I2C时钟分频值

uint8_t I2C_CalculateBRG(uint32_t Fosc, uint32_t I2C_CLOCK) {

    return (Fosc / (4 * I2C_CLOCK)) - 1;

}



void I2C_Init(void) {

    // 计算波特率生成值

    SSPADD = I2C_CalculateBRG(4000000, I2C_CLOCK);



    // 配置I2C控制寄存器

    SSPCON1 = 0b00101000; // 主模式,I2C使能

    SSPCON2 = 0b00000000; // 默认配置



    // 配置I2C引脚

    TRISC2 = 1; // SDA引脚设为输入

    TRISC3 = 1; // SCL引脚设为输入

}



void I2C_Start(void) {

    SEN = 1; // 发送启动条件

    while (SEN); // 等待启动条件完成

}



void I2C_RepeatedStart(void) {

    RSEN = 1; // 发送重复启动条件

    while (RSEN); // 等待重复启动条件完成

}



void I2C_Stop(void) {

    PEN = 1; // 发送停止条件

    while (PEN); // 等待停止条件完成

}



void I2C_WriteByte(uint8_t data) {

    SSPBUF = data; // 写入数据

    while (!BF); // 等待数据传输完成

    BF = 0; // 清除缓冲器标志位

}



uint8_t I2C_ReadByte(void) {

    RCEN = 1; // 使能接收

    while (!BF); // 等待数据接收完成

    uint8_t data = SSPBUF; // 读取数据

    BF = 0; // 清除缓冲器标志位

    return data;

}



uint8_t I2C_ReadByteWithACK(uint8_t ack) {

    RCEN = 1; // 使能接收

    while (!BF); // 等待数据接收完成

    uint8_t data = SSPBUF; // 读取数据

    BF = 0; // 清除缓冲器标志位

    ACKDT = ack; // 设置ACK数据位

    ACKEN = 1; // 使能ACK生成

    while (ACKEN); // 等待ACK生成完成

    return data;

}



void I2C_WriteRegister(uint8_t slaveAddress, uint8_t registerAddress, uint8_t data) {

    I2C_Start();

    I2C_WriteByte(slaveAddress << 1); // 发送从设备地址和写操作位

    I2C_WriteByte(registerAddress); // 发送寄存器地址

    I2C_WriteByte(data); // 发送数据

    I2C_Stop();

}



uint8_t I2C_ReadRegister(uint8_t slaveAddress, uint8_t registerAddress) {

    I2C_Start();

    I2C_WriteByte(slaveAddress << 1); // 发送从设备地址和写操作位

    I2C_WriteByte(registerAddress); // 发送寄存器地址

    I2C_RepeatedStart();

    I2C_WriteByte((slaveAddress << 1) | 1); // 发送从设备地址和读操作位

    uint8_t data = I2C_ReadByteWithACK(0); // 读取数据并发送NACK

    I2C_Stop();

    return data;

}



int main(void) {

    // 初始化I2C

    I2C_Init();



    // 写入一个寄存器

    I2C_WriteRegister(0x50, 0x01, 0xAA);



    // 读取一个寄存器

    uint8_t data = I2C_ReadRegister(0x50, 0x01);

    UART_WriteString("Read data: ");

    UART_WriteChar(data);



    while (1) {

        // 主循环可以处理其他任务

    }



    return 0;

}




I2C通信示例
以下是一个简单的I2C通信示例,展示如何在PIC16单片机和一个I2C从设备(如EEPROM)之间传输数据。假设使用4MHz的振荡器频率,I2C时钟频率为100kHz。

硬件连接:

PIC16的SCL引脚连接到EEPROM的SCL引脚

PIC16的SDA引脚连接到EEPROM的SDA引脚

使用合适的上拉电阻

软件配置:

使用 MPLAB X IDE 进行开发

配置项目为4MHz振荡器频率

编写上述初始化和通信代码

测试:

使用I2C调试工具(如I2C总线分析器)或示波器观察I2C通信
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/2401_87715305/article/details/145273599

使用特权

评论回复
沙发
wahahaheihei| | 2025-1-22 09:57 | 只看该作者
PIC16属于低端的产品吧,中级的是PIC18

使用特权

评论回复
板凳
heisexingqisi| | 2025-1-26 18:46 | 只看该作者
刚开始的单片机就那么几种接口

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

16

主题

54

帖子

0

粉丝