在國外服務器上做網站項目如何賺錢企業(yè)營銷策略分析論文
一、IIC總線的基本概念:
????????iic總線是一種帶應答的同步的、串行、半雙工的通信方式,支持一個主機對應多個從機。它有一根SCL(時鐘線)和一根SDA(數據線)組成,由于只有一根數據線,所以它是半雙工的通信方式。
首先需要了解 主機和從機之間是如何通過 iic 總線進行數據的讀寫的。
二、IIC總線的通信流程:
? ? ? ? 當主機向從機發(fā)送數據時:
1.主機需要發(fā)送一位起始位(時鐘線為高電平,數據線產生下降沿),標志著要開始發(fā)送數據
2.然后主機發(fā)送 7位 的從機地址和 1位 的寫標志(0)
3.此時從機需要回應一個應答信號,表示收到了主機發(fā)送數據的請求
4.主機發(fā)送 8位 從機的寄存器地址,告訴從機發(fā)送的數據保存在哪里
5.從機再次回應一個應答信號
6.主機發(fā)送 8位 的數據
7.從機回應一個應答信號
8.此時發(fā)送完一個字節(jié)的數據,如果需要繼續(xù)發(fā)送數據,重復6、7步
9.當不需要發(fā)送數據時,主機發(fā)起終止信號(時鐘線為高電平,數據線產生上升沿),表示停止發(fā)送數據
? ? ? ? 當主機向從機讀取數據時:
1.主機需要發(fā)送一位起始位,標志著要開始發(fā)送數據
2.然后主機發(fā)送 7位 的從機地址和 1位 的寫標志(0)
3.此時從機需要回應一個應答信號,表示收到了主機發(fā)送數據的請求
4.主機發(fā)送 8位 從機的寄存器地址,告訴從機發(fā)送的數據保存在哪里
5.從機再次回應一個應答信號
6.主機發(fā)起一個重復的起始信號
7.然后主機發(fā)送 7位 的從機地址和 1位 的讀標志(1)
8.從機回應一個應答信號
9.從機可以發(fā)送 8位 數據
10.此時主機可以回應一個應答信號或者非應答信號,表示讀取多少數據
11.當主機不再讀取數據時,上一步回應非應答信號后,再次發(fā)起終止信號,表示停止讀取數據
三、GPIO模擬IIC實現溫濕度傳感器數據的讀取
1.首先需要查看原理圖找到對應的引腳,進行相關初始化的設置。
(1)查詢RCC寄存器,使能GPIOF外設時鐘
(2)查詢GPIO數據手冊,根據需要將相關引腳進行初始化設置
2.了解SI7006溫濕度傳感器的內部結構以及工作原理
查詢SI7006數據手冊,需要了解到以下幾個方面的內容:
(1)如何初始化芯片
????????通過數據手冊了解到對應的寄存器地址,向寄存器地址中寫入初始化的數值。
(2)芯片內部的工作原理
????????SI7006內部有兩個傳感器,分別是溫度傳感器和濕度傳感器,通過模數轉換器,可以將二者采集到的模擬信號轉換為數字信號,再由相關的寄存器存儲,通過控制單元交給IIC接口,再通過IIC總線與外界進行交互
(3)查詢作為IIC從機時的從機地址
????????SI7006數據手冊中已經寫明,但要注意它是原本的從機地址,還是加上了R/W標志位后的數值
(4)采集溫度和濕度的芯片寄存器
? ? ? ? 根據數據手冊查詢到相關的寄存器命令碼,主IIC設備可以使用命令結構與Si7006通信
(5)查詢傳感器采集的數據如何進行計算
? ? ? ? 根據給定的公式可以將采集到的溫濕度轉換成通用的溫濕度打印出來
相關代碼如下:
main.c:
#include "si7006.h"int main()
{//si7006初始化si7006_init();//風扇/馬達的初始化led_init();unsigned short hum;short tem;while(1){//讀取溫度和濕度hum=si7006_read_hum();tem=si7006_read_tem();//計算溫濕度數據hum=hum*125/65536-6;tem=tem*175.72/65536-46.85;printf("hum:%d\n",hum);printf("tem:%d\n",tem);delay_ms(1000);if(tem>26){CH1_CTRL(1);//開啟風扇}else if(tem<=26){CH1_CTRL(0);//關閉風扇}if(hum > 65){//開啟震動馬達//Motor_CTRL(1);GPIOF->ODR |= (0x1<<6);}else if(hum <= 65){//關閉震動馬達//Motor_CTRL(0);GPIOF->ODR &= (~(0x1<<6));}}return 0;
}
si7006.c:
#include "si7006.h"//手動封裝延時函數
void delay_ms(int ms)
{int i,j;for(i=0;i<ms;i++){for(j=0;j<2000;j++){}}
}void si7006_init()
{i2c_init();//1.發(fā)起起始信號i2c_start();//2.發(fā)送7bit從機地址和寫標志位 0X80i2c_write_byte(0x80);//3.等待從機應答i2c_wait_ack();//4.發(fā)送寄存器地址 0XE6i2c_write_byte(0xe6);//5.等待從機應答i2c_wait_ack();//6.向從機發(fā)送數據 0X3Ai2c_write_byte(0x3a);//7.等待從機應答i2c_wait_ack();//8.發(fā)送終止信號i2c_stop();
}unsigned short si7006_read_hum()
{unsigned char hum_l,hum_h;unsigned short hum;// 1.主機發(fā)起起始信號i2c_start();// 2.主機發(fā)送7bit從機地址+1bit寫標志i2c_write_byte(0x80);// 3.等待從機應答i2c_wait_ack();// 4.主機發(fā)送8bit寄存器地址i2c_write_byte(0xe5);// 5.等待從機應答i2c_wait_ack();// 6.主機發(fā)起重復起始信號i2c_start();// 7.主機發(fā)送7bit從機地址+1bit 讀 0X81i2c_write_byte(0x81);// 8.等待從機應答i2c_wait_ack();// 9.延時等待從機測量數據delay_ms(1000);// 10.讀取濕度的高8bit數據 hum_h// 11.發(fā)送應答信號hum_h = i2c_read_byte(0);// 12.讀取濕度的低8位數據 hum_l // 13.發(fā)送非應答信號hum_l = i2c_read_byte(1);// 14.發(fā)起終止信號i2c_stop();// 15.將讀取到的數據的低8位和高8bit合成一個完整的數據hum=hum_h<<8|hum_l;return hum;}short si7006_read_tem()
{unsigned char tem_l,tem_h;unsigned short tem;// 1.主機發(fā)起起始信號i2c_start();// 2.主機發(fā)送7bit從機地址+1bit寫標志i2c_write_byte(0x80);// 3.等待從機應答i2c_wait_ack();// 4.主機發(fā)送8bit寄存器地址i2c_write_byte(0xe3);// 5.等待從機應答i2c_wait_ack();// 6.主機發(fā)起重復起始信號i2c_start();// 7.主機發(fā)送7bit從機地址+1bit 讀 0X81i2c_write_byte(0x81);// 8.等待從機應答i2c_wait_ack();// 9.延時等待從機測量數據delay_ms(1000);// 10.讀取溫度的高8bit數據 tem_h// 11.發(fā)送應答信號tem_h = i2c_read_byte(0);// 12.讀取溫度的低8位數據 tem_l// 13.發(fā)送非應答信號tem_l = i2c_read_byte(1);// 14.發(fā)起終止信號i2c_stop();// 15.將讀取到的數據的低8位和高8bit合成一個完整的數據tem=tem_h<<8|tem_l;return tem;}
si7006.h:
#ifndef __SI7006_H__
#define __SI7006_H__
#include"iic.h"
#include "uart4.h"void delay_ms(int ms);
void si7006_init();
unsigned short si7006_read_hum();
short si7006_read_tem();#endif
i2c.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));// 空閑狀態(tài)SDA和SCL拉高 I2C_SCL_H;I2C_SDA_H;
}/** 函數名:i2c_start* 函數功能:模擬i2c開始信號的時序* 函數參數:無* 函數返回值:無* */
void i2c_start(void)
{/** 開始信號:時鐘在高電平期間,數據線從高到低的變化* --------* SCL \* --------* ----* SDA \* --------* */ //確保SDA是輸出狀態(tài) PF15輸出SET_SDA_OUT;// 空閑狀態(tài)SDA和SCL拉高 I2C_SCL_H;I2C_SDA_H;delay_us();//延時等待一段時間I2C_SDA_L;//數據線拉低delay_us();//延時等待一段時間I2C_SCL_L;//時鐘線拉低,讓總線處于占用狀態(tài)
}/** 函數名:i2c_stop* 函數功能:模擬i2c停止信號的時序* 函數參數:無* 函數返回值:無* */void i2c_stop(void)
{/** 停止信號 : 時鐘在高電平期間,數據線從低到高的變化 * ----------* SCL /* --------* --- -------* SDA X /* --- -------* *///確保SDA是輸出狀態(tài) PF15輸出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 : 等待發(fā)送的字節(jié)數據* 函數返回值: 無* */void i2c_write_byte(unsigned char dat)
{ /** 數據信號:時鐘在低電平期間,發(fā)送器向數據線上寫入數據* 時鐘在高電平期間,接收器從數據線上讀取數據 * ---- --------* SCL \ / \* -------- --------* -------- ------------------ ---* SDA X X* -------- ------------------ ---** 先發(fā)送高位在發(fā)送低位 * *///確保SDA是輸出狀態(tài) 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{//發(fā)送1I2C_SDA_H;}else //最高位為0{I2C_SDA_L;//發(fā)送0}delay_us();//延時//時鐘線拉高,接收器接收I2C_SCL_H;delay_us();//延時,用于等待接收器接收數據delay_us();//延時//將數據左移一位,讓原來第6位變?yōu)榈?位dat = dat<<1;}}/** 函數名:i2c_read_byte* 函數功能: 主機從i2c總線上的從設備讀8bits數據, * 主機發(fā)送一個應答或者非應答信號* 函數參數: 0 : 應答信號 1 : 非應答信號* 函數返回值:讀到的有效數據** */
unsigned char i2c_read_byte(unsigned char ack)
{/** 數據信號:時鐘在低電平期間,發(fā)送器向數據線上寫入數據* 時鐘在高電平期間,接收器從數據線上讀取數據 * ---- --------* SCL \ / \* -------- --------* -------- ------------------ ---* SDA X X* -------- ------------------ ---** 先接收高位, 在接收低位 * */unsigned int i;unsigned char dat;//保存接受的數據//將數據線設置為輸入SET_SDA_IN;for(i=0;i<8;i++){//先把時鐘線拉低,等一段時間,保證發(fā)送器發(fā)送完畢數據I2C_SCL_L;delay_us();delay_us();//保證發(fā)送器發(fā)送完數據//時鐘線拉高,讀取數據I2C_SCL_H;delay_us();dat=dat<<1;//數值左移 一定要先左移在賦值,不然數據會溢出if(I2C_SDA_READ)//pf15管腳得到了一個高電平輸入{dat |=1; //0000 0110}else{dat &=(~0X1);}delay_us();}if(ack){i2c_nack();//發(fā)送非應答信號,不再接收下一次數據}else{i2c_ack();//發(fā)送應答信號 }return dat;//將讀取到的數據返回
}
/** 函數名: i2c_wait_ack* 函數功能: 主機作為發(fā)送器時,等待接收器返回的應答信號* 函數參數:無* 函數返回值:* 0:接收到的應答信號* 1:接收到的非應答信號* */
unsigned char i2c_wait_ack(void)
{/** 主機發(fā)送一個字節(jié)之后,從機給主機返回一個應答信號** -----------* SCL / M:讀 \* ------------- --------* --- ---- --------------------* SDA X X* --- --------------------* 主 釋 從機 主機* 機 放 向數據 讀數據線* 總 線寫 上的數據* 線 數據* */ //時鐘線拉低,接收器可以發(fā)送信號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;//時鐘線拉低,讓數據線處于占用狀態(tài)return 0;}
/** 函數名: iic_ack* 函數功能: 主機作為接收器時,給發(fā)送器發(fā)送應答信號* 函數參數:無* 函數返回值:無* */
void i2c_ack(void)
{/* --------* SCL / \* ------- ------* ---* SDA X * --- -------------* *///保證數據線是輸出SET_SDA_OUT;I2C_SCL_L;//拉低時鐘線delay_us();I2C_SDA_L;//數據線拉低,表示應答信號delay_us();I2C_SCL_H;//時鐘線拉高,等待發(fā)送器讀取應答信號delay_us();//讓從機讀取我們當前的回應delay_us();I2C_SCL_L;//數據線處于占用狀態(tài),發(fā)送器發(fā)送下一次數據}
/** 函數名: iic_nack* 函數功能: 主機作為接收器時,給發(fā)送器發(fā)送非應答信號* 函數參數:無* 函數返回值:無* */
void i2c_nack(void)
{/* --------* SCL / \* ------- ------* --- ---------------* SDA X * --- * */ //保證數據線是輸出SET_SDA_OUT;I2C_SCL_L;//拉低時鐘線delay_us();I2C_SDA_H;//數據線拉高,表示非應答信號delay_us();I2C_SCL_H;//時鐘線拉高,等待發(fā)送器讀取應答信號delay_us();delay_us();I2C_SCL_L;//數據線處于占用狀態(tài),發(fā)送器發(fā)送下一次數據
}
i2c.h:
#ifndef __IIC_H__
#define __IIC_H__
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.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 delay(int ms);
void i2c_init(void);//初始化
void i2c_start(void);//起始信號
void i2c_stop(void);//終止信號
void i2c_write_byte(unsigned char dat);//寫一個字節(jié)數據
unsigned char i2c_read_byte(unsigned char ack);//讀取一個字節(jié)數據
unsigned char i2c_wait_ack(void); //等待應答信號
void i2c_ack(void);//發(fā)送應答信號
void i2c_nack(void);//發(fā)送非應答信號#endif