使用STM32F103C8T6驱动MAX6675读取热电偶数据

博主在网上找到了一些代码支持,但是或多或少的存在一些问题,博主在这里直接上代码了,需要的自己研究就可以了,亲测可用

参考文章:(3条消息) MAX6675使用笔记_自小吃多的博客-CSDN博客

max6675使用说明:(3条消息) MAX6675使用笔记_Delta-delta的博客-CSDN博客

代码说明:

        使用的板子是STM32F103C8T6最小开发板

        代码功能:将6675的数据读取并通过串口传输到串口调试助手上

        spi的部分不知道为什么使用硬件读不出来数据,这里我用的软件模拟,也就是说你可以吧管脚设置到任何一个你需要的管脚上

使用说明:

        1、MAX6675博主是自己焊接的,因为器件很精密,要求焊接温度建议在300℃下不超过15秒。焊接过热可能会导致芯片损坏。

        2、热电偶线路长短会影响数据精度,芯片到MCU的线距会影响时钟频率

        3、一定要对准6675的时钟来,频率不能超过2M,只能慢不能快

        4、在电路设计上,连接接热电偶负极的管脚建议接地,可以提高稳定性

                                        在热电偶正负极之间链接一个100nF的电阻可以减少干扰

(博主后期遇到了大功率用电器启动、运行过程中温度读数清零的现象,通过增加电阻已解决)

main.c

#include "stm32f10x_conf.h"
#include "LED.h"
#include "delay.h"
#include "usart.h"
#include "MAX6675.h"
#include "stdio.h"

void USART1_IRQHandler(void)//这是USART接收到数据后触发的中断处理函数(如果你使用了中断接收的方式)
{
	uint8_t data;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		data = usart1_recv_byte();
		usart1_send_byte(data);
	}
}


int main (void)
{
	float t;
	LED_init();
	delay_init();
	usart1_init();
	MAX6675_Init();
	
	printf("开始检测\n");
	while(1)
	{
		t = read_temper();
		printf("%.5f\n", t);
//		t = MAX6675_ReadReg();
//		print_binary(t);
		printf("\n");
		LED_on();
		delay_ms(1000);
		LED_off();
		delay_ms(1000);
	}
}






MAX6675.h

#ifndef __MAX6675_H
#define __MAX6675_H
 
#include "stm32f10x_conf.h"

/*============================================================*/
/*SPI1管脚设置为:											  */
/*		PA4 -> cs片选				PA5 -> SCK时钟		      */
/*		PA6 -> MISO主出从入			PA7 -> MOSI 主出从入		  */
/*============================================================*/


void MAX6675_Init(void);								//初始化
unsigned int MAX6675_ReadReg(void);			//读取全部16位数据
float read_temper(void);									//读取温度
void print_binary(unsigned int number);		//这是打印二进制数的打印函数
	
 
#endif


MAX6675.c

#include "MAX6675.h"
#include "delay.h"
#include "usart.h"	
#include "stdio.h"

/*==========================================================*/
/*SPI1管脚设置为:											*/
/*		PA4 -> cs片选			PA5 -> SCK时钟		        */
/*		PA6 -> MISO主出从入		PA7 -> MOSI 主出从入			*/
/*==========================================================*/

void MAX6675_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;  		//GPIO初始化结构体
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA, ENABLE );     //使能APB2总线上的GPIOA组时钟
	
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
//配置PIN4, 5管脚			 
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; 		 						//设置模式为推挽输出
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;								//输出速率为50MHz
	GPIO_Init(GPIOA, &GPIO_InitStruct);
	GPIO_SetBits(GPIOA, GPIO_Pin_4);									 //拉高片选线电平
	GPIO_ResetBits(GPIOA, GPIO_Pin_5);                                  //拉低时钟线
	
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;							//MISO管脚
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;	//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStruct);
}

unsigned int MAX6675_ReadReg(void)
{ 
	unsigned char i;   
	unsigned int dat;
	 
	i   = 0;   
	dat = 0; 	
	GPIO_ResetBits(GPIOA, GPIO_Pin_4);		//拉低片选开始传输
  GPIO_ResetBits(GPIOA, GPIO_Pin_5);	//拉低时钟准备传输   
	delay_us(2);
	for(i=0; i<16; i++) 
	{      
		GPIO_SetBits(GPIOA, GPIO_Pin_5);	//拉高时钟线
		delay_us(1);
		dat = dat<<1;                    
		if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6)==1)   
			dat = dat|0x01;
		GPIO_ResetBits(GPIOA, GPIO_Pin_5);//拉低时钟结束传输  
			delay_us(1);
	} 
	GPIO_SetBits(GPIOA, GPIO_Pin_4);  //拉高片选,传输结束
	delay_us(2);
	return dat;   
}

float read_temper()					//读取温度
{
  int d;
  d=MAX6675_ReadReg();			//读取当前温度
	d = d<<1;                //去掉伪符号位
		if(d&0x08) 	//MAX6675是否在线
			printf("未检测到热电偶");
		else
			printf("设备在线");

		return ((d>>4)&0x0fff)*0.25;
}

void print_binary(unsigned int number) {
    if (number >> 1) {
        print_binary(number >> 1);
    }
    putc((number & 1) ? '1' : '0', stdout);
}

delay.h

#ifndef __DELAY_H
#define __DELAY_H

#include "stm32f10x_conf.h" 

#define SYSCLK 72				

extern void delay_init(void);					//初始化函数
extern void delay_ms(uint16_t nms);		//毫秒级别的延迟
extern void delay_us(uint32_t nus);		//纳秒级别的延迟

#endif


delay.c

#include "delay.h"

static uint8_t  fac_us=0; //us延时倍乘数			   
static uint16_t fac_ms=0; //ms延时倍乘数

void delay_init(void)
{
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
	//为系统定时器选择时钟为	HCLK 8分频	72MHz/8 = 9MHz
	fac_us = SYSCLK / 8;
	//微秒的倍乘数 = 72 / 8 = 9
	//X * fac_us就相当于有X个微秒
	fac_ms = (u16)fac_us * 1000; 
	//每个ms需要的systick时钟数(1ms = 1000us),所以fac_us*1000
	//X * fac_ms就相当于有X个毫秒
}

void delay_us(uint32_t nus)//微秒级别的延迟
{
	uint32_t midtime;
	//定义了一个uint32_t的变量																			//保存寄存器的状态
	SysTick->LOAD/*重装载值寄存器*/ = nus * fac_us;
	//时间加载(相当于有nus个微妙)
	SysTick->VAL = 0x00;
	//清空当前值寄存器,以为系统会自动去重装载值寄存器去加载
	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
	//给状态及控制寄存器的第0位(是否开启)至1,相当于打开了计时器
	do
	{
		midtime = SysTick->CTRL;
		//把状态及控制寄存器的数据赋值给变量
	}
	while((midtime & 0x01) && !(midtime & (1 << 16)));
	//当第0位(是否开启)是1,并且第16位(判断计数器是否记到0)到0的时候跳出循环
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;	
	//给状态及控制寄存器的第0位(是否开启)至0,相当于关闭了计时器
	SysTick->VAL = 0X00;
	//清空当前值寄存器
}

void delay_xms(uint16_t nms)
{	 		  	  
	uint32_t midtime;		   
	SysTick->LOAD = (uint32_t)nms*fac_ms;									//时间加载(SysTick->LOAD为24bit)
	SysTick->VAL = 0x00;															//清空计数器
	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;					//开始倒数
	do
	{
		midtime = SysTick->CTRL;
	}
	while((midtime & 0x01) && !(midtime & (1 << 16)));//等待时间到达
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;	//关闭计数器
	SysTick->VAL = 0X00;															//清空计数器
} 

void delay_ms(u16 nms)
{	 	 
	u8 repeat = nms / 540;	//记录有多少个整的540ms
	u16 remain = nms % 540;	//记录有多少个不够540ms
	//理论上只要小于1864都可以,不一定非得是540
	while(repeat)
	{
		delay_xms(540);
		repeat--;
	}
	if(remain)delay_xms(remain);
} 




usart.h

#ifndef __USART_H
#define __USART_H

#include "stm32f10x_conf.h"
/*================================================*/
/*由开发手册总线图可知,C8T6的USART1在APB1总线上	*/
/*				USART1_TX段在PA9管脚										*/
/*				发送管脚需要配置为推挽的复用功能				*/
/*				USART1_RX段在PA10管脚										*/
/*				接收管脚需要配置为浮空的输入功能				*/
/*================================================*/
typedef void(*usart1_handler)(uint8_t);									//定义了函数指针类型

extern void usart1_init(void);											//初始化USART1的函数
extern void usart1_send_byte(uint8_t);							//通过USART1发送一个字节
extern void usart1_send_data(uint8_t* buff);				//通过USART1发送数据
extern uint8_t usart1_recv_byte(void);							//通过USART1接收一个字节
extern void set_usart1_handler(usart1_handler h);		//接收中断函数


#endif





usart.c

#include "usart.h"
#include "stdio.h"
/*============================宏定义部分=================================*/

#pragma import(__use_no_semihosting)//这是标准库需要的支持函数

/*============================变量定义===================================*/
struct __FILE												//弱定义(两个下划线)一下FILE类型
{
		int a;
};

FILE __stdout;											//弱定义一下标准输出

void _sys_exit(int x)								//重定义函数,这步操作相当于禁用半主机模式
{
	
}

int fputc(int c, FILE *f)//把fputc重定向到USART1的发送
{
	usart1_send_byte(c);
	return c;
}

/*============================函数实现===================================*/

void usart1_init(void)							//USART1的初始化函数
{
	GPIO_InitTypeDef GPIO_Value;			//定义了初始化GPIO的结构体类型的变量
	USART_InitTypeDef USART_Value;		//定义了初始化USART的结构体类型的变量
	NVIC_InitTypeDef NVIC_Value;			//定义了初始化NVIC的结构体类型的变量
	
	//使能APB2总线上的GPIOA组的时钟,和UASART1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
/*从芯片开发手册的总线图上可以查看你的串口在那条总线上,
	后面的管脚服用列表也可以看你的输入输出的管脚,使能对应组的时钟即可*/
	
	
	GPIO_Value.GPIO_Mode = GPIO_Mode_AF_PP;				//选择了推挽的复用模式
	GPIO_Value.GPIO_Pin = GPIO_Pin_9;							//选择了9号管脚
	GPIO_Value.GPIO_Speed = GPIO_Speed_50MHz;			//选择了50MHz的输出速率
	GPIO_Init(GPIOA, &GPIO_Value);								//按照上述配置初始化GPIOA组的管脚
	
	GPIO_Value.GPIO_Mode = GPIO_Mode_IN_FLOATING;	//选择了浮空的输入模式
	GPIO_Value.GPIO_Pin = GPIO_Pin_10;						//选择了10号管脚
	GPIO_Init(GPIOA, &GPIO_Value);								//按照上述配置初始化GPIOA组的管脚
	
	USART_Value.USART_BaudRate = 115200;					//选择了115200的波特率
	USART_Value.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//选择了关闭硬件流控
	USART_Value.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//选择了发送和接收模式
	USART_Value.USART_Parity = USART_Parity_No;		//选择了没有奇偶校验
	USART_Value.USART_StopBits = USART_StopBits_1;//选择了1个停止位
	USART_Value.USART_WordLength = USART_WordLength_8b;//选择了8个数据位
	USART_Init(USART1, &USART_Value);							//按照上述配置初始化USART1

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置组优先级和子优先级的所占比例
	NVIC_Value.NVIC_IRQChannel = USART1_IRQn;			//选择了USART1的中断号
	NVIC_Value.NVIC_IRQChannelCmd = ENABLE;				//使能该中断
	NVIC_Value.NVIC_IRQChannelPreemptionPriority = 2;//配置组优先级的级别为2
	NVIC_Value.NVIC_IRQChannelSubPriority = 2;		//配置子优先级的级别为2
	NVIC_Init(&NVIC_Value);												//按照上述配置初始化NVIC

	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	//把USART1的接收配置为中断的模式

	USART_Cmd(USART1, ENABLE);										//选择了使能USART1的功能
}

void usart1_send_byte(uint8_t data)							//通过USART1发送数据
{
	USART1->SR;																		//读取SR寄存器
	USART_SendData(USART1, data);									//把形参data存储的数据通过USART1进行发送
	while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
	//以死等的方式等待USART1的数据发送成功
	USART_ClearFlag(USART1, USART_FLAG_TC);				//清除USART1的发送成功的标志状态
}


void usart1_send_data(uint8_t*buf)								//通过USART1发送多个字节数据
{
	while(*buf)
	{
		usart1_send_byte(*buf);
		buf++;
	}
}


uint8_t usart1_recv_byte(void)												//通过USART1接收数据
{
	uint8_t data = 0;																		//用于保存接收到的数据
	
	if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)//判断USART1是否接收到了数据
	{
		data = USART_ReceiveData(USART1);									//读取USART1接收到的数据
		USART_ClearFlag(USART1, USART_FLAG_RXNE);					//清除USART1接收数据的标志状态
	}
	return data;//把读取到的数据返回
}



欢迎在文章下讨论分享问题,博主虽然也是小白,但也会尽力的帮助解决问题的~~

  • 6
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值