博主在网上找到了一些代码支持,但是或多或少的存在一些问题,博主在这里直接上代码了,需要的自己研究就可以了,亲测可用
参考文章:(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;//把读取到的数据返回
}
欢迎在文章下讨论分享问题,博主虽然也是小白,但也会尽力的帮助解决问题的~~