IO口模拟SPI总线

SPI是一种全双工同步串行接口,四总线结构SCK、MOSI、MISO、CS分别是时钟、主机输出、主机接收、片选。其中各个厂商的写法可能不一致。SPI总线有四种工作模式,在不再做介绍。最常用的SPI总线时序CS为低时SCK上冲沿数据有效,数据从MISO、MOSI输入和输出。我们只要有这个概念就行,具体时序可以直接看芯片手册。很多芯片都集成了SPI总线接口,没有SPI接口的芯片同样可以用IO口模拟其时序加深理解其时序。最近工作中也用到了SPI接口,闲暇之余用SISI软件用51单片机IO口模拟SPI总线和25LC1024 EEPROM通信。电路连接如下:

用25LC1024的两种操作方式来测试IO口模拟的SPI,这种两种方式分别是连续读、连续写。当然还有其他操作方式如擦写等。连续读、连续写时序如下:

连续读方式:

读操作流程:读指令->24bit地址->数据

连续读的时序:


写数据时首先发送读指令和24bit的地址。值得注意的是整个过程CS总是为低的,中间不能跳回高电平。之前我没有注意导致了读写失败。


连续写方式:

写操作比较特殊,具体流程比读操作多一个使能:写使能->写指令->24bit地址->数据

写使能命令时序:


发送了写使能之后就可以进一步操作,写时序如下:


测试思路:将0到15的七段数码管十六进制模数据写入到SPI EEPROM中然后读出,再用七段数码管显示出来具体代码如下:

#include <reg51.h>
#include<intrins.h>//包含_nop_()函数

//定义命令
#define READ 0x03
#define WRITE 0x02
#define WREN 0x06
#define WRDI 0x04
#define RDSR 0x05
#define WRSR 0x01
#define PE 0x42
#define SE 0xd8
#define CE 0xc7
#define RDID 0xab
#define DPD 0xb9

//端口定义
sbit SCK = P1^4;
sbit MOSI = P1^5;
sbit MISO = P1^6;
sbit CS = P1^7;

//延时程序
void delay_ms(int n)
{
	int i, j;
	for(i=0;i<n;++i)
	for(j=0;j<1000;++j);
}

//延时程序
void delay_ns(void) //延时>4us
{
	_nop_();//空指令
	_nop_();
	_nop_();
	_nop_();
}

//SPI写一个byte
void SPI_byte_write(const char *dat)
{
	char tmp = *dat, i;
	
	for(i=0;i<8;++i){
		SCK = 0;
		MOSI = (bit)(tmp >> 7); //先输出高bit
		tmp <<= 1; //数据左移一位
		SCK = 1; //SCK为高发送bit
		delay_ns(); //延时防止芯片为响应
	}
}

//SPI读一个byte
void SPI_byte_read(char *dat)
{
	char tmp = 0, i;

	for(i=0;i<8;++i){
		SCK = 0;
		tmp <<= 1; //左移一位
		tmp |= MISO; //接收最高位
		SCK = 1;//SCK为高接收bit
		delay_ns();
	}
	
	*dat = tmp;
}

//SPI写多个byte	
void SPI_nbyte_write(const char *addr, const char *dat, char num)
{
	char inst_wren = WREN, inst_write = WRITE, i;
	
	CS = 0;
	SPI_byte_write(&inst_wren); //写使能
	CS = 1;
	
	delay_ms(1);
	
	CS = 0;
	SPI_byte_write(&inst_write); //写指令
	
	for(i=0;i<3;++i){
		SPI_byte_write(addr + i);//写地址
	}
	
	for(i=0;i<num;++i){
		SPI_byte_write(dat + i);//写数据
	}
	
	CS = 1;
}

//SPI读多个byte
void SPI_nbyte_read(const char *addr, char *dat, char num)
{
	char inst = READ, i;
	
	CS = 0;
	SPI_byte_write(&inst); //读指令
	
	for(i=0;i<3;++i){
		SPI_byte_write(addr + i);//写地址
	}
	
	for(i=0;i<num;++i){
		SPI_byte_read(dat + i);//写数据
	}
	CS = 1;
}

char dat[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
				0x77,0x7c,0x39,0x5e,0x79,0x71};//0~F的字形码
char save[16] = {0};

const char addr[3] = {0x00, 0x00, 0x00};//读写的地址

int main(void)
{
   int i;
   SPI_nbyte_write(addr, dat, 16);//写入数据
   delay_ms(30);
   SPI_nbyte_read(addr, save, 16);//读出数据
   for(i=0;i<16;i++)
   {
		P3=save[i];//数码管显示
		delay_ms(60);
	}
	return 0;
}

源代码地址:http://download.csdn.net/detail/a16839678/6394585





### 回答1: BL0939是一款数字温湿度传感器,通常使用SPI与主控芯片通信。下面是一个使用C语言模拟BL0939的SPI驱动的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #define SPI_MODE 0 /* SPI模式,0表示模式0,CPOL=0,CPHA=0 */ /* 模拟SPI总线IO */ #define MOSI_PIN 1 /* MOSI */ #define MISO_PIN 2 /* MISO */ #define SCK_PIN 3 /* 时钟 */ #define CS_PIN 4 /* 片选 */ /* 定义BL0939寄存器地址 */ #define BL0939_TEMPERATURE_REG 0x00 #define BL0939_HUMIDITY_REG 0x01 /* 模拟SPI总线传输一个字节 */ uint8_t spi_transfer(uint8_t data) { uint8_t recv_data = 0; int i; for (i = 7; i >= 0; i--) { /* 先将时钟置低 */ digitalWrite(SCK_PIN, 0); /* 将数据写入MOSI */ digitalWrite(MOSI_PIN, (data >> i) & 1); /* 模拟SPI传输延迟 */ delay(1); /* 拉高时钟,读取MISO的数据 */ recv_data |= digitalRead(MISO_PIN) << i; digitalWrite(SCK_PIN, 1); /* 模拟SPI传输延迟 */ delay(1); } return recv_data; } /* 从BL0939读取温度数据 */ float bl0939_read_temperature() { uint8_t tx_data[3] = {0x03, BL0939_TEMPERATURE_REG, 0x00}; uint8_t rx_data[3]; /* 拉低片选 */ digitalWrite(CS_PIN, 0); /* 发送读取温度命令和寄存器地址 */ int i; for (i = 0; i < 3; i++) { spi_transfer(tx_data[i]); } /* 接收温度数据 */ for (i = 0; i < 3; i++) { rx_data[i] = spi_transfer(0); } /* 拉高片选 */ digitalWrite(CS_PIN, 1); /* 计算温度值 */ int16_t temp_raw = (rx_data[1] << 8) | rx_data[2]; return (float)temp_raw / 100.0; } /* 从BL0939读取湿度数据 */ float bl0939_read_humidity() { uint8_t tx_data[3] = {0x03, BL0939_HUMIDITY_REG, 0x00}; uint8_t rx_data[3]; /* 拉低片选 */ digitalWrite(CS_PIN, 0); /* 发送读取湿度命令和寄存器地址 */ int i; for (i = 0; i < 3; i++) { spi_transfer(tx_data[i]); } /* 接收湿度数据 */ for (i = 0 ### 回答2: 在C语言中实现BL0939的模拟IOSPI驱动,可以采用以下步骤: 1.定义必要的引脚和寄存器的宏: 首先,我们需要定义与BL0939连接的引脚和相关寄存器的宏。这些宏将帮助我们在代码中方便地访问这些引脚和寄存器。 2.编写初始化函数: 初始化函数应包含引脚和寄存器的初始化,以及SPI的设置。这些包括设置引脚为输出或输入,配置SPI控制器的参数(如数据位数、时钟速度等)。 3.编写发送数据函数: 发送数据函数用于向BL0939写入数据。首先,我们将写入片选信号使BL0939响应。然后,我们可以使用SPI控制器发送数据。 4.编写接收数据函数: 接收数据函数用于从BL0939读取数据。首先,我们将写入片选信号使BL0939响应。然后,我们可以使用SPI控制器接收数据。 5.编写其他必要的功能函数: 根据BL0939的需求,可能还需要编写其他的功能函数。这些函数可以包括设置寄存器、读取状态等。 6.编写主函数: 在主函数中,我们可以使用上述编写的函数进行测试。我们可以编写代码以模拟与BL0939的交互,例如设置寄存器的值并读取其状态。 需要注意的是,由于无法直接访问硬件,我们在编写完整代码后,可以使用模拟器或硬件评估板进行测试。此外,还应仔细阅读BL0939的数据手册以了解其具体的IOSPI驱动要求。 ### 回答3: BL0939是一种模拟IOSPI(Serial Peripheral Interface)驱动芯片。要用C语言实现BL0939的模拟IOSPI驱动,首先需要了解BL0939的通信协议和功能。 BL0939通信协议基于SPI的主从模式,其中主设备发送的数据帧由8位控制字和8位数据字组成,从设备通过IO进行通信。下面是一个简单的C语言示例代码,展示了如何实现BL0939的模拟IOSPI驱动。 ```c #include <stdio.h> #include <wiringPi.h> // 定义BL0939的IO #define BL0939_CS 10 #define BL0939_CLK 11 #define BL0939_IN 12 #define BL0939_OUT 13 // 初始化BL0939的IO void bl0939_init() { wiringPiSetup(); pinMode(BL0939_CS, OUTPUT); pinMode(BL0939_CLK, OUTPUT); pinMode(BL0939_IN, INPUT); pinMode(BL0939_OUT, OUTPUT); } // 发送数据帧到BL0939 void bl0939_send_frame(unsigned char control, unsigned char data) { digitalWrite(BL0939_CS, LOW); // 使能BL0939 // 发送控制字 for (int i = 7; i >= 0; i--) { digitalWrite(BL0939_CLK, LOW); // 下降沿时发送位 digitalWrite(BL0939_OUT, (control >> i) & 0x01); digitalWrite(BL0939_CLK, HIGH); // 上升沿时采样位 } // 发送数据字 for (int i = 7; i >= 0; i--) { digitalWrite(BL0939_CLK, LOW); // 下降沿时发送位 digitalWrite(BL0939_OUT, (data >> i) & 0x01); digitalWrite(BL0939_CLK, HIGH); // 上升沿时采样位 } digitalWrite(BL0939_CS, HIGH); // 禁止BL0939 } int main() { bl0939_init(); // 初始化BL0939的IO unsigned char control = 0x01; // 控制字 unsigned char data = 0x55; // 数据字 bl0939_send_frame(control, data); // 发送数据帧到BL0939 return 0; } ``` 在上述示例代码中,首先定义了BL0939的IO引脚,并在`bl0939_init`函数中进行了初始化。然后在`bl0939_send_frame`函数中对控制字和数据字进行SPI通信,按位发送位和采样位。 在`main`函数中,定义了控制字和数据字,并调用`bl0939_send_frame`函数发送数据帧到BL0939。 需要注意的是,以上代码仅为示例,实际使用时还需要根据具体的硬件平台及接线进行适配和调整。同时还需要根据BL0939的功能文档,结合具体的需求进行更详细的代码编写。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值