软件/硬件SPI主从通信讲解以及代码(MAX6675温度检测)

        上一篇文章我讲了如何从零开始通过看数据手册上手一款新接触的芯片(MAX6675温度检测),下面是博客的链接,感兴趣的可以先去看一下。

教你如何上手使用一款新的芯片&精准的温度检测方案MAX6675ISA热电偶到数字转换器-CSDN博客

        之前这篇文章只是讲述了原理和步骤,没有讲代码实现部分,今天给大家讲一下主从通信以及代码实现部分。从两方面讲,先说硬件的SPI,再说软件模拟的SPI。

        先讲一下SPI的主从通信原理,SPI的时钟信号SCL只能由主机提供,从机是根据主机提供的SCL时钟信号来进行收发数据的,从机不能主动给主机发送数据。MOSI中 M是主机 O是输出 S是从机 I是输入,很好理解这个就是主机输出从机输入,是主机给从机发送数据的,同理MISO是从机给主机发送数据的。当使用的是一主一从的通信方式时,NSS引脚可以直接拉低默认选中从机,如果是一主多从,就要通过NSS来选择要通信的从机设备。

        主机发送时钟信号,同时会在MOSI上向从机发送数据,同时还会从MISO上读取从机发送的数据,同理从机在接收到时钟信号时,同步接收数据的同时也会发送数据到主机,所以一个时钟信号主机和从机直接就交换了一个bit的数据。

        从MAX6675的数据手册可以看到,它通信时还需要一个CS片选信号,需要一个下降沿来通知从机开始通信,所以我们在做主从机通信是还需要去留意芯片的数据手册中的时序图。

        下面以MAX6675通信为例子(16位数据)

        可以看到CS先是拉低,表示选中,然后开始传输数据。

        根据SPI协议,16位数据为0000 0110 0100 0001

        不太清楚SPI通信协议的可以看我另外一篇文章,里面讲的比较详细。

        硬件SPI+DMA驱动ST7789芯片(超详细讲解)(合宙AIR001)-CSDN博客

        下面是硬件SPI的代码部分,硬件SPI的系统配置这里不做过多的讲解,感兴趣的可以看我的另外一篇文章,里面有较为详细的介绍。硬件SPI+DMA驱动ST7789芯片(超详细讲解)(合宙AIR001)-CSDN博客

        根据上面的时序图介绍,我们需要一个CS片选引脚,所以我们先定义一个引脚作为CS使用,并且初始化成推完输出模式,不同的库的初始化函数不一样,下面是我的展示,大家自行修改。

#define MAX6675_CS1_PORT  GPIOA
#define MAX6675_CS1_PIN   GPIO_PIN_4
#define MAX6675_CS1_SET   HAL_GPIO_WritePin(MAX6675_CS1_PORT, MAX6675_CS1_PIN,1);
#define MAX6675_CS1_CLE   HAL_GPIO_WritePin(MAX6675_CS1_PORT, MAX6675_CS1_PIN,0);

void max6675_init(void)
{
	GPIO_InitTypeDef CS = {.Pin = GPIO_PIN_4,.Mode = GPIO_MODE_OUTPUT_PP,};
	__HAL_RCC_GPIOA_CLK_ENABLE();
	HAL_GPIO_Init(GPIOA, &CS);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4,1);


} 

       根据数据手册可知有效位是D14-D3,热电偶检测是D2(开路为1,默认为0)

        下面是获取从机(MAX6675芯片)的数据

        HAL_SPI_TransmitReceive_DMA(&Spi1Handle, (uint8_t *)TxBuff,(uint8_t *)RxBuff,2);函数是DMA同时读写内容的函数,TxBuff是发送数据的地址,RxBuff是接收数据的地址。

        从上面的数据含义可以知道,热电偶检测是D2(开路为1,默认为0),所以如果热电偶开路则直接输出4095。数据的有效位是D14-D3,所以直接右移3位即可得到。

uint8_t TxBuff[2] = {0xFF,0X00};
uint8_t RxBuff[2] = {0,0};

uint16_t max6675_readRawValue(void)
{
  uint16_t tmp;
  
  MAX6675_CS1_CLE;
  HAL_SPI_TransmitReceive_DMA(&Spi1Handle, (uint8_t *)TxBuff,(uint8_t *)RxBuff,2);
  tmp=RxBuff[0];
  tmp <<= 8;
  tmp |= RxBuff[1];
  MAX6675_CS1_SET;

  if (tmp & 4) 
  {
    // thermocouple open
    tmp = 4095; //未检测到热电偶
  }
  else 
  {
    tmp = tmp >> 3;
  }
  return tmp;
}

        下面是数据转换成温度的处理,具体关系可以看我另外一篇文章教你如何上手使用一款新的芯片&精准的温度检测方案MAX6675ISA热电偶到数字转换器-CSDN博客

float max6675_readTemperature(void)
{
  return (max6675_readRawValue() * 1024.0 / 4096.0);
}

        最后是配置串口输出一下数据看是否正确

printf("%f",max6675_readTemperature());

        串口输出正常,温度正常,成功实现。

        下面是用软件来模拟SPI读取数据

        软件模拟SPI读取数据需要配置3个引脚,CS、SCL、SO(MISO)

        初始化的时候注意CS、SCL配置成推挽输出,SO要配置成浮空输入,这里不要搞错。

#define MAX6675_CS1_PORT  GPIOA
#define MAX6675_CS1_PIN   GPIO_PIN_4
#define MAX6675_CS1_SET   HAL_GPIO_WritePin(MAX6675_CS1_PORT, MAX6675_CS1_PIN,1);
#define MAX6675_CS1_CLE   HAL_GPIO_WritePin(MAX6675_CS1_PORT, MAX6675_CS1_PIN,0);


#define MAX6675_SCL        GPIOF
#define MAX6675_SCL_PIN    GPIO_PIN_1
#define MAX6675_SCL_SET    HAL_GPIO_WritePin(MAX6675_SCL, MAX6675_SCL_PIN,1);
#define MAX6675_SCL_CLE    HAL_GPIO_WritePin(MAX6675_SCL, MAX6675_SCL_PIN,0);


#define MAX6675_SO        GPIOF
#define MAX6675_SO_PIN    GPIO_PIN_0


void max6675_init(void)
{
	GPIO_InitTypeDef CS = {.Pin = GPIO_PIN_4,.Mode = GPIO_MODE_OUTPUT_PP,};
	__HAL_RCC_GPIOA_CLK_ENABLE();
	HAL_GPIO_Init(GPIOA, &CS);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4,1);
		
	GPIO_InitTypeDef SO = {.Pin = MAX6675_SO_PIN,.Mode = GPIO_MODE_INPUT,};
	__HAL_RCC_GPIOF_CLK_ENABLE();
	HAL_GPIO_Init(MAX6675_SO, &SO);
	HAL_GPIO_WritePin(MAX6675_SO, MAX6675_SO_PIN,0);
				
	GPIO_InitTypeDef SCL = {.Pin = MAX6675_SCL_PIN,.Mode = GPIO_MODE_OUTPUT_PP,};
	__HAL_RCC_GPIOF_CLK_ENABLE();
	HAL_GPIO_Init(MAX6675_SCL, &SCL);
	HAL_GPIO_WritePin(MAX6675_SCL, MAX6675_SCL_PIN,0);



}

        下面是软件模拟的读取数据函数,现将CS拉低,然后用引脚的高低电平模拟出SCL的时钟信号,同时将SO上的数据逐个读出 。

uint16_t read(void)
{
	uint16_t count;	
	MAX6675_CS1_CLE;
	//HAL_Delay(1);
	for(int i=0;i<16;i++)
	{
		MAX6675_SCL_SET;
		count|=HAL_GPIO_ReadPin(MAX6675_SO,MAX6675_SO_PIN);
		if(i<=14)
			count=count<<1;
		MAX6675_SCL_CLE;
		HAL_Delay(1);
	}
	//HAL_Delay(1);
	MAX6675_CS1_SET;
	 if (count & 4) 
  {
    // thermocouple open
    count = 4095; //未检测到热电偶
  }
  else 
  {
    count = count >> 3;
  }

	return count;
}

        下面是温度转换函数 

float get_tem()
{
	return(read()* 1024.0 / 4096.0);
}

        最后打印出数据,验证代码 

printf("%f",get_tem());
        成功实现,完结撒花。

         我最近建了一个嵌入式的QQ交流群,感兴趣的可以进群了解一下,我会在群里分享一些常用的代码封装,以及一些项目的源码。QQ群讨论也是完全开放,只要不打广告大家可以就嵌入式尽情的沟通和交流,大家对文章中的内容有疑问也可以在群中提出,有空会尽我所能给大家一些帮助。QQ群号:643408467

MAX6675是一款用于测量温度的数字隔离传感器模块,它能够通过I²C(Inter-Integrated Circuit)通信接口进行数据传输。ISA+T(Intelligent System Architecture Temperature Sensor)通常指这款传感器配合特定的ISA协议栈的编程。 编程MAX6675ISA+T主要是通过编写软件来控制传感器读取温度并处理数据。以下是一般的步骤: 1. **库函数引入**:首先需要在你的项目中包含MAX6675的驱动库,许多微控制器开发板如Arduino、树莓派等都有预编写的库文件可以直接使用。 2. **初始化硬件**:使用适当的API连接到I²C,并设置传感器地址(默认是0x48)。 ```c int sensorAddress = 0x48; // I2C address of the MAX6675 Wire.begin(); // Initialize I2C library ``` 3. **配置传感器**:设置相关的配置选项,例如是否启用温度补偿功能等。 ```c uint8_t configCommand = 0b00000011; // Enable temperature measurement Wire.write(sensorAddress, &configCommand); ``` 4. **读取数据**:发送命令请求温度值,然后接收和解析从传感器返回的数据。 ```c uint8_t command[] = {0x44}; // Read temperature command (0x44 = MEASURE) Wire.write(sensorAddress, command); delay(1); // Allow time for the measurement uint16_t reading; Wire.read(sensorAddress, sizeof(reading), &reading); float temperature = ((float)reading / 16384.0) * 204.8 - 40.0; // Convert to Celsius ``` 5. **异常处理和错误检查**:确保所有的I²C操作成功并且数据校验无误。 6. **循环监测**:如果持续监控温度,可以将上述步骤放入一个无限循环中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值