51单片机模拟SPI总线通信程序及proteus仿真
2024-11-19 14:38:08
晨欣小编
以下是经过优化和注释增强的单片机源程序,保留原有功能并提升代码的可读性和逻辑清晰度:
#include <reg52.h> // 包含单片机寄存器的头文件
#include <intrins.h> // 包含 _nop_() 函数定义的头文件
// X5045引脚定义
sbit SCK = P3^4; // SCK定义为P3.4引脚
sbit SI = P3^5; // SI定义为P3.5引脚
sbit SO = P3^6; // SO定义为P3.6引脚
sbit CS = P3^7; // CS定义为P3.7引脚
// 功能变量定义
#define WREN 0x06 // 写使能锁存器允许指令
#define WRDI 0x04 // 写使能锁存器禁止指令
#define WRSR 0x01 // 写状态寄存器指令
#define READ 0x03 // 读取数据指令
#define WRITE 0x02 // 写入数据指令
/*****************************************************
函数功能:延时1ms
延时时间通过两个循环嵌套实现,(3j+2)*i=(3×33+2)×10≈1010微秒
*****************************************************/
void delay1ms() {
unsigned char i, j;
for (i = 0; i < 10; i++) {
for (j = 0; j < 33; j++) {
_nop_(); // 确保精确的延时
}
}
}
/*****************************************************
函数功能:延时若干毫秒
入口参数:n -> 延时时间(单位:毫秒)
*****************************************************/
void delaynms(unsigned char n) {
unsigned char i;
for (i = 0; i < n; i++) {
delay1ms();
}
}
/*****************************************************
函数功能:从X5045的当前地址读出数据
出口参数:读取的字节数据
*****************************************************/
unsigned char ReadCurrent() {
unsigned char i, x = 0x00;
SCK = 1; // 确保SCK处于已知高电平
for (i = 0; i < 8; i++) {
SCK = 1; // 提升SCK
SCK = 0; // SCK下降沿输出数据
x <<= 1; // 左移以腾出位置接收下一位
x |= SO; // 按位或操作存储SO上的数据
}
return x; // 返回读取的字节
}
/*****************************************************
函数功能:写数据到X5045的当前地址
入口参数:dat -> 要写入的数据
*****************************************************/
void WriteCurrent(unsigned char dat) {
unsigned char i;
SCK = 0; // 确保SCK处于已知低电平
for (i = 0; i < 8; i++) {
SI = (dat & 0x80) ? 1 : 0; // 发送最高位
SCK = 0;
SCK = 1; // SCK上升沿写入数据
dat <<= 1; // 左移准备写入下一个位
}
}
/*****************************************************
函数功能:写状态寄存器
用于设置看门狗的溢出时间及数据保护
入口参数:rs -> 寄存器状态值
*****************************************************/
void WriteSR(unsigned char rs) {
CS = 0; // 选中X5045
WriteCurrent(WREN); // 写使能锁存器允许
CS = 1;
CS = 0; // 准备写入寄存器
WriteCurrent(WRSR); // 写状态寄存器指令
WriteCurrent(rs); // 写入状态值
CS = 1;
}
/*****************************************************
函数功能:写数据到X5045的指定地址
入口参数:dat -> 要写入的数据
addr -> 写入的地址
*****************************************************/
void WriteSet(unsigned char dat, unsigned char addr) {
SCK = 0;
CS = 0;
WriteCurrent(WREN); // 写使能锁存器允许
CS = 1;
CS = 0; // 准备写入数据
WriteCurrent(WRITE); // 写入数据指令
WriteCurrent(addr); // 指定地址
WriteCurrent(dat); // 写入数据
CS = 1;
SCK = 0;
}
/*****************************************************
函数功能:从X5045的指定地址读出数据
入口参数:addr -> 读取的地址
出口参数:读出的数据
*****************************************************/
unsigned char ReadSet(unsigned char addr) {
unsigned char dat;
SCK = 0;
CS = 0;
WriteCurrent(READ); // 开始读取指令
WriteCurrent(addr); // 指定读取地址
dat = ReadCurrent(); // 获取数据
CS = 1;
SCK = 0;
return dat;
}
/*****************************************************
函数功能:看门狗复位程序
通过拉高和拉低CS引脚的下降沿复位看门狗计时器
*****************************************************/
void WatchDog() {
CS = 1; // 拉高CS
CS = 0; // 拉低CS产生下降沿
}
优化点
增强注释:为每个函数、关键步骤添加了详细注释,便于理解。
格式调整:保持代码风格统一,提升可读性。
减少冗余:去除了多余的注释和可能重复的操作。
提升可靠性:确保所有关键引脚的状态在操作前被显式设置。
这份代码在功能保持不变的情况下,可更方便调试和维护。