IIC和SPI结合实现室内温度计

iic.h

#ifndef __IIC_H__
#define __IIC_H__
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.h"
#include "gpio.h"
/* 通过程序模拟实现I2C总线的时序和协议* GPIOF ---> AHB4* I2C1_SCL ---> PF14* I2C1_SDA ---> PF15** */#define SET_SDA_OUT     do{GPIOF->MODER &= (~(0x3 << 30)); \GPIOF->MODER |= (0x1 << 30);}while(0)
#define SET_SDA_IN      do{GPIOF->MODER &= (~(0x3 << 30));}while(0)#define I2C_SCL_H       do{GPIOF->BSRR |= (0x1 << 14);}while(0)
#define I2C_SCL_L       do{GPIOF->BRR |= (0x1 << 14);}while(0)#define I2C_SDA_H       do{GPIOF->BSRR |= (0x1 << 15);}while(0)
#define I2C_SDA_L       do{GPIOF->BRR |= (0x1 << 15);}while(0)#define I2C_SDA_READ    (GPIOF->IDR & (0x1 << 15))void delay_us(void);
void i2c_init(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_write_byte(unsigned char  dat);
unsigned char i2c_read_byte(unsigned char ack);
unsigned char i2c_wait_ack(void);       
void i2c_ack(void);
void i2c_nack(void);#endif 

SI7006.H

#ifndef __SI7006_H__
#define __SI7006_H__#include "iic.h"
#define        SI7006_SLAVE      0x40void si7006_init(void);short si7006_read_data(unsigned char slave_addr, unsigned char reg_addr);#endif //__SI7006_H__

spi.h

#ifndef __SPI_H__
#define __SPI_H__#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.h"
// MOSI对应的引脚输出高低电平的信号
#define  MOSI_OUTPUT_H()    do{GPIOE->ODR |= (0x1 << 14);}while(0)
#define  MOSI_OUTPUT_L()    do{GPIOE->ODR &= (~(0x1 << 14));}while(0)// 对应595芯片的锁存引脚输出高低电平
#define  NSS_OUTPUT_H()     do{GPIOE->ODR |= (0x1 << 11);}while(0)
#define  NSS_OUTPUT_L()     do{GPIOE->ODR &= (~(0x1 << 11));}while(0)// 时钟信号对应的引脚输出高低电平
#define  SCK_OUTPUT_H()     do{GPIOE->ODR |= (0x1 << 12);}while(0)
#define  SCK_OUTPUT_L()     do{GPIOE->ODR &= (~(0x1 << 12));}while(0)/** 函数功能: SPI初始化函数,推挽输出,高速,禁止上拉和下拉* 函数参数:无* 函数返回值:无
*/
void SPI_init(void);
/** 函数功能:SPI发送数据的函数* 函数参数:dat : 要发送的数据* 函数返回值:无*
*/
void SPI_write(unsigned char dat);#endif

iic.c

#include "iic.h"extern void printf(const char* fmt, ...);
/** 函数名 : delay_us* 函数功能:延时函数* 函数参数:无* 函数返回值:无* */
void delay_us(void)
{unsigned int i = 2000;while(i--);
}
/** 函数名 : i2c_init* 函数功能: i2C总线引脚的初始化, 通用输出,推挽输出,输出速度,* 函数参数:无* 函数返回值:无* */
void i2c_init(void)
{// 使能GPIOF端口的时钟RCC->MP_AHB4ENSETR |= (0x1 << 5);// 设置PF14,PF15引脚为通用的输出功能GPIOF->MODER &= (~(0xF << 28));GPIOF->MODER |= (0x5 << 28);// 设置PF14, PF15引脚为推挽输出GPIOF->OTYPER &= (~(0x3 << 14));// 设置PF14, PF15引脚为高速输出GPIOF->OSPEEDR |= (0xF << 28);// 设置PF14, PF15引脚的禁止上拉和下拉GPIOF->PUPDR &= (~(0xF << 28));// 空闲状态SDA和SCL拉高 I2C_SCL_H;I2C_SDA_H;
}/** 函数名:i2c_start* 函数功能:模拟i2c开始信号的时序* 函数参数:无* 函数返回值:无* */
void i2c_start(void)
{/** 开始信号:时钟在高电平期间,数据线从高到低的变化*     --------* SCL         \*              --------*     ----* SDA     \*          --------* */	//保证数据线PF15是输出SET_SDA_OUT;//空闲状态时钟线和数据线拉高I2C_SCL_H;I2C_SDA_H;delay_us();I2C_SDA_L;//数据线拉低delay_us();I2C_SCL_L;//时钟线拉低,此时I2C总线处于占用状态
}/** 函数名:i2c_stop* 函数功能:模拟i2c停止信号的时序* 函数参数:无* 函数返回值:无* */void i2c_stop(void)
{/** 停止信号 : 时钟在高电平期间,数据线从低到高的变化 *             ----------* SCL        /*    --------*    ---         -------* SDA   X       /*    --- -------* */SET_SDA_OUT;I2C_SCL_L;//方便讲数据线电频拉低delay_us();I2C_SDA_L;delay_us();I2C_SCL_H;delay_us();I2C_SDA_H;}/** 函数名: i2c_write_byte* 函数功能:主机向i2c总线上的从设备写8bits数据* 函数参数:dat : 等待发送的字节数据* 函数返回值: 无* */void i2c_write_byte(unsigned char dat)
{/** 数据信号:时钟在低电平期间,发送器向数据线上写入数据* 			时钟在高电平期间,接收器从数据线上读取数据 *      ----          --------* 	SCL     \        /        \*           --------          --------*      -------- ------------------ ---* 	SDA         X                  X*      -------- ------------------ ---**      先发送高位在发送低位 * *///确保SDA是输出状态 PF15输出SET_SDA_OUT;unsigned int i;for(i=0;i<8;i++){//时钟线拉低I2C_SCL_L;delay_us();//延时//0X3A->0011 1010   0X80->10000000if(dat&0X80)//最高位为1{//发送1I2C_SDA_H;}else  //最高位为0{I2C_SDA_L;//发送0}delay_us();//延时//时钟线拉高,接收器接收I2C_SCL_H;delay_us();//延时,用于等待接收器接收数据delay_us();//延时//将数据左移一位,让原来第6位变为第7位dat = dat<<1;}}/** 函数名:i2c_read_byte* 函数功能: 主机从i2c总线上的从设备读8bits数据, *          主机发送一个应答或者非应答信号* 函数参数: 0 : 应答信号   1 : 非应答信号* 函数返回值:读到的有效数据** */
unsigned char i2c_read_byte(unsigned char ack)
{/** 数据信号:时钟在低电平期间,发送器向数据线上写入数据* 			时钟在高电平期间,接收器从数据线上读取数据 *      ----          --------* 	SCL     \        /        \*           --------          --------*      -------- ------------------ ---* 	SDA         X                  X*      -------- ------------------ ---**      先接收高位, 在接收低位 * */unsigned int i;unsigned char dat;//保存接受的数据//将数据线设置为输入SET_SDA_IN;for(i=0;i<8;i++){//先把时钟线拉低,等一段时间,保证发送器发送完毕数据I2C_SCL_L;delay_us();delay_us();//保证发送器发送完数据//时钟线拉高,读取数据I2C_SCL_H;       delay_us();dat=dat<<1;//数值左移  0000 0000if(I2C_SDA_READ)//pf15管脚得到了一个高电平输入{dat |=1; //0000 0110}else{dat &=(~0X1);}delay_us();}if(ack){i2c_nack();//发送非应答信号,不再接收下一次数据}else{i2c_ack();//发送应答信号 }return dat;
}
/** 函数名: i2c_wait_ack* 函数功能: 主机作为发送器时,等待接收器返回的应答信号* 函数参数:无* 函数返回值:*					0:接收到的应答信号*                  1:接收到的非应答信号* */
unsigned char i2c_wait_ack(void)
{/** 主机发送一个字节之后,从机给主机返回一个应答信号**                   -----------* SCL              /   M:读    \*     -------------             --------*     --- ---- --------------------* SDA    X    X*     ---      --------------------*     主  释   从机    主机*     机  放   向数据  读数据线*         总   线写    上的数据*         线   数据* */	//时钟线拉低,接收器可以发送信号I2C_SCL_L;I2C_SDA_H;//先把数据线拉高,当接收器回应应答信号时,数据线会拉低delay_us();SET_SDA_IN;//设置数据线为输入delay_us();//等待接收方向数据线写入delay_us();I2C_SCL_H;//用于读取数据线数据if(I2C_SDA_READ)//PF15得到一个高电平输入,收到非应答信号return 1;I2C_SCL_L;//时钟线拉低,让数据线处于占用状态return 0;
} 
/** 函数名: iic_ack* 函数功能: 主机作为接收器时,给发送器发送应答信号* 函数参数:无* 函数返回值:无* */
void i2c_ack(void)
{/*            --------* SCL       /        \*    -------          ------*    ---* SDA   X *    --- -------------* *///保证数据线是输出SET_SDA_OUT;I2C_SCL_L;//拉低时钟线delay_us();I2C_SDA_L;//数据线拉低,表示应答信号delay_us();I2C_SCL_H;//时钟线拉高,等待发送器读取应答信号delay_us();delay_us();I2C_SCL_L;//数据线处于占用状态,发送器发送下一次数据
}
/** 函数名: iic_nack* 函数功能: 主机作为接收器时,给发送器发送非应答信号* 函数参数:无* 函数返回值:无* */
void i2c_nack(void)
{/*            --------* SCL       /        \*    -------          ------*    --- ---------------* SDA   X *    --- * *///保证数据线是输出SET_SDA_OUT;I2C_SCL_L;//拉低时钟线delay_us();I2C_SDA_H;//数据线拉高,表示非应答信号delay_us();I2C_SCL_H;//时钟线拉高,等待发送器读取应答信号delay_us();delay_us();I2C_SCL_L;//数据线处于占用状态,发送器发送下一次数据	
}

si7006.c

#include "iic.h"
#include "si7006.h"
extern void delay(unsigned int ms);
/** 函数名:si7006_init* 函数功能:SI7006芯片的初始化* 函数参数:无* 函数返回值:无
*/
void si7006_init(void)
{i2c_init();i2c_start();i2c_write_byte(SI7006_SLAVE << 1);i2c_wait_ack();i2c_write_byte(0xE6);i2c_wait_ack();i2c_write_byte(0x3A);i2c_wait_ack();i2c_stop();}
/** 函数名:si7006_read_data* 函数功能:读取SI7006的转换结果* 函数参数:*     slave_addr : 从机地址*     reg_addr : 寄存器地址* 函数返回值:无
*/
short si7006_read_data(unsigned char slave_addr, unsigned char reg_addr)
{short dat;unsigned char dat_h, dat_l;i2c_start();i2c_write_byte(slave_addr << 1);i2c_wait_ack();i2c_write_byte(reg_addr);i2c_wait_ack();i2c_start();i2c_write_byte((slave_addr << 1) | 1);i2c_wait_ack();delay(10);  // 等待转换结束dat_h = i2c_read_byte(0);//读取高八位数据,响应一个应答信号dat_l = i2c_read_byte(1);i2c_stop();dat = dat_h;dat <<= 8;dat |= dat_l;return dat;
}

spi.c

#include "spi.h"
/* SPI4_NSS     ---->   PE11* SPI4_SCK     ---->   PE12* SPI4_MOSI    ---->   PE14* SPI4_MISO    ---->   PE13* *//* 数码管的编码, 先发送低位,在发送高位* A B C D E F G DP* 1 1 1 1 1 1 0 0    0xFC   0* 0 1 1 0 0 0 0 0    0x60   1* 1 1 0 1 1 0 1 0    0xDA   2* 1 1 1 1 0 0 1 0    0xF2   3* 0 1 1 0 0 1 1 0    0x66   4* 1 0 1 1 0 1 1 0    0xB6   5 * 1 0 1 1 1 1 1 0    0xBE   6* 1 1 1 0 0 0 0 0    0xE0   7* 1 1 1 1 1 1 1 0    0xFE   8* 1 1 1 1 0 1 1 0    0xF6   9* */
void delay_us1(unsigned int us)
{int i,j;for(i = 0; i < us;i++)for (j = 0; j < 1;j++);
}void SPI_init(void)
{//使能GPIOE时钟RCC->MP_AHB4ENSETR |= (0x1 << 4);// MOSI    PE14 输出GPIOE->MODER &= (~(0x3 << 28));GPIOE->MODER |= (0x1 << 28);//推挽GPIOE->OTYPER &= (~(0x1 << 14));//低速GPIOE->OSPEEDR &= (~(0x3 << 28));
//  GPIOE->OSPEEDR |= (0x2 << 28);GPIOE->PUPDR &= (~(0x3 << 28));// MISO    PE13  输入GPIOE->MODER &= (~(0x3 << 26));GPIOE->OSPEEDR &= (~(0x3 << 26));
//  GPIOE->OSPEEDR |= (0x2 << 26);//无上拉下拉GPIOE->PUPDR &= (~(0x3 << 26));// SCK     PE12 输出GPIOE->MODER &= (~(0x3 << 24));GPIOE->MODER |= (0x1 << 24);GPIOE->OTYPER &= (~(0x1 << 12));GPIOE->OSPEEDR &= (~(0x3 << 24));
//  GPIOE->OSPEEDR |= (0x2 << 24);GPIOE->PUPDR &= (~(0x3 << 24));// NSS     PE11  输出GPIOE->MODER &= (~(0x3 << 22));GPIOE->MODER |= (0x1 << 22);GPIOE->OTYPER &= (~(0x1 << 11));GPIOE->OSPEEDR &= (~(0x3 << 22));
//  GPIOE->OSPEEDR |= (0x2 << 22);GPIOE->PUPDR &= (~(0x3 << 22));NSS_OUTPUT_L();    // 595芯片的锁存引脚拉低SCK_OUTPUT_L();    // SPI的时钟线拉低
}void SPI_write(unsigned char dat)
{unsigned char i;for(i = 0; i < 8; i++){if(dat & 0x01){MOSI_OUTPUT_H();  // MOSI线写高} else {MOSI_OUTPUT_L();  // MOSI线写低}dat >>= 1;// 时钟线从低电平到高电平的变化时,MOSI数据线上的数据// 被写到595芯片的移位寄存器中   SCKcSCK_OUTPUT_L();   // SCK拉低delay_us1(10);SCK_OUTPUT_H();   // SCK拉高delay_us1(10);}//NSS_OUTPUT_L();//NSS_OUTPUT_H();}

main.c

#include "spi.h"#include "si7006.h"extern void printf(const char *fmt, ...);void delay(int ms){int i, j;for (i = 0; i < ms; i++){for (j = 0; j < 2000; j++);}}int num[10] = {0xFC,0x60,0xDA,0xF2,0x66,0xB6,0x3E,0xE0,0xFE,0xF6};int main(){unsigned short tem1; //用于保存 温度数据和湿度数据//进行SI7e06的初始化si7006_init();SPI_init();while (1){//读取温度tem1 = si7006_read_data(0x40, 0XE3);//数据转换tem1 = tem1 * 175.72 / 65536 - 46.85;int tem = (int)tem1;//数据输出printf("tem:%d\n", tem);for(int j=0;j<1000;j++){if (tem > 9 && tem <= 99){for (int i = 2; i < 4; i++){SPI_write(0x80 >> i);if (i == 2){SPI_write(num[tem/10] );}if (i == 3){SPI_write(num[tem%10]);}NSS_OUTPUT_L();delay(1);NSS_OUTPUT_H();}}}}return 0;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/221837.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

facebook广告的门槛有哪些

Facebook广告的门槛主要包括以下几个方面&#xff1a; 账户资格&#xff1a;需要拥有一个有效的Facebook个人账号或商业账号。 账户状态&#xff1a;个人账号需要满足一定活跃度要求&#xff0c;而商业账号则需要满足公司名称和地址等详细信息的要求。 账户安全性&#xff1a…

每日一题:Leetcode974.和可被k整除的子数组

题目描述&#xff1a; 给定一个整数数组 nums 和一个整数 k &#xff0c;返回其中元素之和可被 k 整除的&#xff08;连续、非空&#xff09; 子数组 的数目。 子数组 是数组的 连续 部分。 示例 1&#xff1a; 输入&#xff1a;nums [4,5,0,-2,-3,1], k 5 输出&#xff1…

什么是PHPUnit?如何进行单元测试?

PHPUnit 是一个用于 PHP 的单元测试框架&#xff0c;它支持测试驱动开发&#xff08;TDD&#xff09;和行为驱动开发&#xff08;BDD&#xff09;。PHPUnit 提供了一套用于编写和运行测试的工具和断言方法。 以下是使用 PHPUnit 进行单元测试的基本步骤&#xff1a; 步骤 1: …

【LeetCode刷题笔记(4)】【Python】【移动零】【简单】

文章目录 题目描述示例 1示例 2提示 解决方案题意拆解双指针算法双指针法的主要优点双指针法的使用场景举例&#xff1a; 解决方案&#xff1a;【双指针一次遍历】解题心得方案代码运行结果复杂度分析 结束语 移动零 题目描述 给定一个数组 nums&#xff0c;编写一个函数将所…

代码随想录第三十一天(一刷C语言)|无重叠区间划分字母区间合并区间

创作目的&#xff1a;为了方便自己后续复习重点&#xff0c;以及养成写博客的习惯。 一、无重叠区间 思路&#xff1a;参考carl文档 按照右边界排序&#xff0c;从左向右记录非交叉区间的个数。最后用区间总数减去非交叉区间的个数就是需要移除的区间个数了。 ledcode题目&a…

多线程------ThreadLocal详解

目录 1. 什么是 ThreadLocal&#xff1f; 2. 如何使用 ThreadLocal&#xff1f; 3. ThreadLocal 的作用 4. ThreadLocal 的应用场景 5. ThreadLocal 的注意事项 我的其他博客 ThreadLocal 是 Java 中一个很有用的类&#xff0c;它提供了线程局部变量的支持。线程局部变量…

家政服务小程序预约上门,让服务更便捷

随着人们生活节奏的加快&#xff0c;家政服务行业越来越受到人们的欢迎。为了满足市场需求&#xff0c;提高服务质量&#xff0c;家政公司需要开发一款预约上门的家政服务小程序。本文将详细介绍如何制作一个预约上门的家政服务小程序。 一、登录乔拓云网后台 首先&#xff0c…

模块二——滑动窗口:438.找到字符串中所有字母异位词

文章目录 题目描述算法原理滑动窗口哈希表 代码实现 题目描述 题目链接&#xff1a;438.找到字符串中所有字母异位词 算法原理 滑动窗口哈希表 因为字符串p的异位词的⻓度⼀定与字符串p 的⻓度相同&#xff0c;所以我们可以在字符串s 中构造⼀个⻓度为与字符串p的⻓度相同…

【Stm32-F407】Keil uVision5 下新建工程

①双击鼠标左键打开Keil uVision5&#xff0c;选择 Project 下的 New uVision Project &#xff1b; ②在期望的文件夹下创建一个工程&#xff0c;并按如下要求操作&#xff1b; ③添加文件类型&#xff0c;按如下要求操作 ④如有需要可添加相关启动文件在工程文件夹下并添加到…

深度学习中的高斯分布

1 高斯分布数学表达 1.1 什么是高斯分布 高斯分布(Gaussian Distribution)又称正态分布(Normal Distribution)。高斯分布是一种重要的模型&#xff0c;其广泛应用与连续型随机变量的分布中&#xff0c;在数据分析领域中高斯分布占有重要地位。高斯分布是一个非常常见的连续概…

ArrayList与顺序表(带完整实例)

【本节目标】 1. 线性表 2. 顺序表 3. ArrayList的简介 4. ArrayList使用 5. ArrayList的扩容机制 6. 扑克牌 1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表…

Mysql 计算地理位置信息

mysql 处理空间关系 MySQL提供了一系列的函数来帮助我们处理空间对象之间的关系&#xff0c;如 ST_Intersects、ST_Contains 等。这些函数可以帮助我们判断空间对象之间的位置关系&#xff0c;并在此基础上执行相应的查询。 多边形查询 在实际应用中&#xff0c;需要查询某个…

【CSS 渐变Gradient详解】线性渐变、径向渐变、锥形渐变及重复渐变

渐变 gradient https://developer.mozilla.org/zh-CN/docs/Web/CSS/gradient https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_images/Using_CSS_gradients CSS 属性值定义语法 https://developer.mozilla.org/zh-CN/docs/Web/CSS/angle https://developer.mozilla.org/…

HTTP 301错误:永久重定向,大勇的冒险之旅

大家好&#xff0c;我是大勇&#xff0c;一个喜欢冒险的程序员。今天&#xff0c;我要和大家分享一个我在互联网世界中的冒险故事——如何处理HTTP 301错误&#xff1a;永久重定向。 那天&#xff0c;我像往常一样&#xff0c;打开我的代码编辑器&#xff0c;准备开始一天的工…

代码随想录算法训练营第36天|● 435. 无重叠区间 ● 763.划分字母区间 ● 56. 合并区间

435. 无重叠区间 已解答 中等 相关标签 相关企业 给定一个区间的集合 intervals &#xff0c;其中 intervals[i] [start(i), end(i)] 。返回 需要移除区间的最小数量&#xff0c;使剩余区间互不重叠 。 示例 1: 输入: intervals [[1,2],[2,3],[3,4],[1,3]]输出: 1解释: 移除…

Wireshark抓包实验

实验目的&#xff1a; 通过实验掌握下列知识&#xff1a; 掌握Wireshark抓包工具的使用。掌握建立telnet用户密码登录方式&#xff0c;并通过wireshark抓取相关信息。理解TCP的包结构&#xff0c;并掌握TCP建立连接的过程。掌握使用tftp工具&#xff0c;上传、下载文件操作及t…

Python实现多种图像去噪方法

Python实现多种图像去噪方法&#xff1a;中值滤波&#xff0c;均值滤波&#xff0c;高通滤波&#xff0c;低通滤波&#xff0c;高斯滤波&#xff0c;同态滤波 图像和视频逐渐成为人们生活中信息获取的重要来源。人们准确地获取信源发出的图像和视频信息需要保证在传输过程中的…

​ctypes --- Python 的外部函数库​

源代码: Lib/ctypes ctypes 是 Python 的外部函数库。它提供了与 C 兼容的数据类型&#xff0c;并允许调用 DLL 或共享库中的函数。可使用该模块以纯 Python 形式对这些库进行封装。 ctypes 教程 注&#xff1a;本教程中的示例代码使用 doctest 来保证它们能正确运行。 由于有…

文本每行数据乘以0.8

文本中数据计算 1.读取input.txt文本中每行数字 2.每行数字乘以0.8&#xff0c;输出到out.txt文件中 package mainimport ("bufio""fmt""log""os""strconv" )func main() {// 打开输入文件inputFile, err : os.Open(&quo…

Ganache结合内网穿透实现远程或不同局域网进行连接访问

文章目录 前言1. 安装Ganache2. 安装cpolar3. 创建公网地址4. 公网访问连接5. 固定公网地址 前言 Ganache 是DApp的测试网络&#xff0c;提供图形化界面&#xff0c;log日志等&#xff1b;智能合约部署时需要连接测试网络。 Ganache 是一个运行在本地测试的网络,通过结合cpol…