性无码一区二区三区在线观看,少妇被爽到高潮在线观看,午夜精品一区二区三区,无码中文字幕人妻在线一区二区三区,无码精品国产一区二区三区免费

ReCclay
認證:VIP會員
所在專題目錄 查看專題
藍橋嵌入式之 按鍵控制LED閃爍
藍橋嵌入式之 蜂鳴器
藍橋嵌入式之 LCD使用
藍橋嵌入式之 簡單USART通信實現(xiàn)LCD顯示
藍橋嵌入式之 AT24C02
藍橋嵌入式之 PWM波輸出相關(guān)總結(jié)
作者動態(tài) 更多
【FPGA基礎(chǔ)】基于 Pango Design Suite(PDS) 的FPGA開發(fā)流程
2021-05-14 11:22
【FPGA基礎(chǔ)】基于Quartus Prime 17.1 的FPGA開發(fā)流程
2021-05-08 17:49
【AD快速入門】8051最小系統(tǒng)繪制
2021-04-22 10:03
藍橋嵌入式之 ADC電壓采集與顯示
2021-04-14 11:48
藍橋嵌入式之 實時時鐘RTC
2021-04-13 14:50

藍橋嵌入式之 AT24C02

工程可見Github<傳送門>


關(guān)于24C02的基礎(chǔ)知識,之前有過很詳細的一篇文章,這里就不再贅述,直接上菜吧。

以下用到的位帶區(qū)及位帶別名區(qū)的相關(guān)知識可參考這里。

eeprom記錄上電次數(shù)這樣一個實例,來鞏固下eeprom。

一、主要代碼

main.c

/*******************************************************************************
* 文件名:main.c
* 描  述:
* 作  者:CLAY
* 版本號:v1.0.0
* 日  期: 2019年1月25日
* 備  注:EEPROM記錄開機次數(shù),LCD顯示開機次數(shù)
*         
*******************************************************************************
*/

#include "config.h"
#include "led.h"
#include "key.h"
#include "timer.h"
#include "beep.h"
#include "lcd.h"
#include "stdio.h"
#include "usart.h"
#include "i2c.h"
#include "eeprom.h"

int main(void)
{
	u8 cnt; //程序啟動次數(shù)
	u8 chk; //啟動次數(shù)校驗字節(jié)
	u8 str1[25];
	
	u8 i;
	u8 str[25];
	u8 temp = 30;
	float AO = 3.845;
	
	STM3210B_LCD_Init();
	LCD_Clear(Blue);
	LEDInit();
	KeyInit();
	BeepInit();
	TIM2Init(2000, 72);//定時2ms
	USART2Init(9600);
	I2CInit();
	
	cnt = E2ReadByte(0x00);
	chk = E2ReadByte(0x01);
	if((cnt^chk) != 0xFF)//兩個字節(jié)不是反碼,歸0重新計數(shù)
	{
		cnt = 0;
	}
	if(cnt < 250)
	{
		cnt ++;
	}
	LCD_ClearLine(Line8);
	sprintf((char*)str1," cnt = %d ",cnt);
	LCD_DisplayStringLine(Line8, str1);
	E2WriteByte(0x00, cnt);
	E2WriteByte(0x01, ~cnt);
	
	LCD_DisplayStringLine(Line1,(u8*) "qwertyuioplkjhgfdsazxcvb");
	sprintf((char*)str,"temp=%d   A0=%.1f  ",temp, AO);
	LCD_DisplayStringLine(Line2,str);
	
	while(1)
	{	
		KeyDriver();
		if(RxdOverFlag)
		{
			RxdOverFlag = 0;
			LCD_ClearLine(Line5);
			LCD_DisplayStringLine(Line5, RxdBuf);
			USART2_SendByte(RxdBuf);
			for(i=0; i<50; i++) RxdBuf[i] = 0;//清空串口接收緩沖區(qū)
			USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//開啟串口接收中斷,處理下一幀數(shù)據(jù)
		} 
	}
}

void KeyAction(int code)
{
	if(code == 1)//按下B1,切換燈狀態(tài),蜂鳴器鳴叫0.1s
	{
		GPIOC->ODR ^= (1<<8);//PC8不斷取反
		GPIOD->ODR |= (1<<2);//PD2置1,使能573鎖存器
		GPIOD->ODR &= ~(1<<2);//PD2清0,關(guān)閉573鎖存器
		Beep(100);
	}
	else if(code == 2)
	{
		Beep(-1);
	}
	else if(code == 3)
	{
		Beep(0);
	}
}



i2c.c

#include "i2c.h"

void I2CInit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOB時鐘       
    GPIO_SetBits(GPIOB, GPIO_Pin_6|GPIO_Pin_7);           //SCL和SDA初始輸出高電平(先設(shè)置引腳電平可以避免IO初始化過程中可能產(chǎn)生的毛刺)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;  //選擇SCL和SDA引腳
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;      //選擇開漏輸出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;     //輸出速率10MHz
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/* 產(chǎn)生總線起始信號 */
void I2CStart(void)
{
    I2C_SDA_OUT = 1; //首先確保SDA、SCL都是高電平
    I2C_SCL_OUT = 1;
    delay_us(5);
    I2C_SDA_OUT = 0; //先拉低SDA
    delay_us(5);
    I2C_SCL_OUT = 0; //再拉低SCL
}

/* 產(chǎn)生總線停止信號 */
void I2CStop(void)
{
    I2C_SCL_OUT = 0; //首先確保SDA、SCL都是低電平
    I2C_SDA_OUT = 0;
    delay_us(5);
    I2C_SCL_OUT = 1; //先拉高SCL
    delay_us(5);
    I2C_SDA_OUT = 1; //再拉高SDA
    delay_us(5);
}

/* I2C總線寫操作,dat-待寫入字節(jié),返回值-從機應(yīng)答位的值 */
u8 I2CWrite(u8 dat)
{
    int i;
    u8 ack;   //用于暫存應(yīng)答位的值
    
    for (i=0; i<8; i++)  //循環(huán)將8bit數(shù)據(jù)輸出到總線上
    {
        I2C_SDA_OUT = (dat&0x80) ? 1 : 0; //將最高位的值輸出到SDA上
        delay_us(5);
        I2C_SCL_OUT = 1; //拉高SCL
        delay_us(5);
        I2C_SCL_OUT = 0; //再拉低SCL,完成一個位周期
        dat <<= 1;       //左移將次高位變?yōu)樽罡呶?,實現(xiàn)高位在先低位在后的發(fā)送順序
    }
    I2C_SDA_OUT = 1;  //8位數(shù)據(jù)發(fā)送完后,主機釋放SDA,以檢測從機應(yīng)答
    delay_us(5);
    I2C_SCL_OUT = 1;  //拉高SCL
    ack = I2C_SDA_IN; //讀取此時的SDA值,即為從機的應(yīng)答值
    delay_us(5);
    I2C_SCL_OUT = 0;  //再拉低SCL完成應(yīng)答位,并保持住總線        
    delay_us(5);
    
    return (!ack); //應(yīng)答值取反以符合通常的邏輯:
                   //0=不存在或忙或?qū)懭胧。?=存在且空閑或?qū)懭氤晒?}

/* I2C總線讀取8位數(shù)據(jù),返回值-讀到的字節(jié) */
u8 I2CRead(void)
{
    int i;
    u8 dat = 0; //數(shù)據(jù)接收變量賦初值0
    
    I2C_SDA_OUT = 1;    //首先確保主機釋放SDA
    for (i=0; i<8; i++) //循環(huán)將總線上的8bit數(shù)據(jù)讀入dat中
    {
        delay_us(5);
        I2C_SCL_OUT = 1;    //拉高SCL
        dat <<= 1;          //左移將己讀到的位向高位移動,實現(xiàn)高位在先低位在后的接收順序
        if(I2C_SDA_IN != 0) //讀取SDA的值到dat最低位上
        {
            dat |= 0x01;    //SDA為1時設(shè)置dat最低位為1,SDA為0時無操作,即仍為初始值的0
        }
        delay_us(5);
        I2C_SCL_OUT = 0;    //再拉低SCL,以使從機發(fā)送出下一位
    }
    return dat;
}

/* I2C總線讀操作,并發(fā)送非應(yīng)答信號,返回值-讀到的字節(jié) */
u8 I2CReadNAK(void)
{
    u8 dat;
    
    dat = I2CRead();  //讀取8位數(shù)據(jù)
    I2C_SDA_OUT = 1;  //8位數(shù)據(jù)讀取完后,拉高SDA,發(fā)送非應(yīng)答信號
    delay_us(5);
    I2C_SCL_OUT = 1;  //拉高SCL
    delay_us(5);
    I2C_SCL_OUT = 0;  //再拉低SCL完成非應(yīng)答位,并保持住總線
    delay_us(5);
    
    return dat;
}

/* I2C總線讀操作,并發(fā)送應(yīng)答信號,返回值-讀到的字節(jié) */
u8 I2CReadACK(void)
{
    u8 dat;
    
    dat = I2CRead();  //讀取8位數(shù)據(jù)
    I2C_SDA_OUT = 0;  //8位數(shù)據(jù)讀取完后,拉低SDA,發(fā)送應(yīng)答信號
    delay_us(5);
    I2C_SCL_OUT = 1;  //拉高SCL
    delay_us(5);
    I2C_SCL_OUT = 0;  //再拉低SCL完成應(yīng)答位,并保持住總線
    delay_us(5);
    
    return dat;
}

i2c.h

#ifndef _I2C_H
#define _I2C_H

#include "config.h"

#define I2C_SCL_OUT   PB_OUT(6)
#define I2C_SDA_OUT   PB_OUT(7)
#define I2C_SDA_IN    PB_IN(7)

void I2CInit(void);
void I2CStart(void);
void I2CStop(void);
u8 I2CReadNAK(void);
u8 I2CReadACK(void);
u8 I2CWrite(u8 dat);


#endif

eeprom.c

#include "i2c.h"
#include "eeprom.h"

/* 讀取EEPROM中的一個字節(jié),addr-字節(jié)地址 */
u8 E2ReadByte(u8 addr)
{
    u8 dat;
    
    do { //用尋址操作查詢當(dāng)前是否可進行讀寫
        I2CStart();
        if (I2CWrite(0x50<<1)) //尋址器件,應(yīng)答則跳出循環(huán),否則繼續(xù)查詢
        {
            break;
        }
        I2CStop();
    } while(1);
    I2CWrite(addr);           //寫入存儲地址
    I2CStart();               //發(fā)送重復(fù)啟動信號
    I2CWrite((0x50<<1)|0x01); //尋址器件,后續(xù)為讀操作
    dat = I2CReadNAK();       //讀取一個字節(jié)數(shù)據(jù)
    I2CStop();
    
    return dat;
}

/* 向EEPROM中寫入一個字節(jié),addr-字節(jié)地址 */
void E2WriteByte(u8 addr, u8 dat)
{
    do { //用尋址操作查詢當(dāng)前是否可進行讀寫
        I2CStart();
        if (I2CWrite(0x50<<1)) //尋址器件,應(yīng)答則跳出循環(huán),否則繼續(xù)查詢
        {
            break;
        }
        I2CStop();
    } while(1);
    I2CWrite(addr);  //寫入存儲地址
    I2CWrite(dat);   //寫入一個字節(jié)數(shù)據(jù)
    I2CStop();
}

eeprom.h

#ifndef _EEPROM_H
#define _EEPROM_H

#include "config.h"

u8 E2ReadByte(u8 addr);
void E2WriteByte(u8 addr, u8 dat);

#endif

config.c

#include "config.h"

/* 1/4微秒延時函數(shù)(含函數(shù)調(diào)用及返回時間共計耗時約1/4微妙@72MHz主頻) */
void delay_qus(void)
{
	__ASM ("nop");
	__ASM ("nop");
	__ASM ("nop");
	__ASM ("nop");
	__ASM ("nop");
	__ASM ("nop");
	__ASM ("nop");
	__ASM ("nop");
}

/* 微秒延時函數(shù),us-延時時間 */
void delay_us(u16 us)
{
	while (us--)
	{
		delay_qus();
		delay_qus();
		delay_qus();
		delay_qus();
	}
}

/* 毫秒延時函數(shù),ms-延時時間 */
void delay_ms(u16 ms)
{
    while (ms--)
    {
        delay_us(1000);
    }
}

config.h

#ifndef _CONFIG_H
#define _CONFIG_H

#include "stm32f10x.h"


//位帶宏定義
#define BITBAND(addr, bitnum)   ((addr&0xF0000000) + 0x2000000 + ((addr&0xFFFFF)<<5) + (bitnum<<2))
#define MEM_ADDR(addr)          *((volatile unsigned long  *)(addr))
#define BIT_ADDR(addr, bitnum)  MEM_ADDR(BITBAND(addr, bitnum))

//IO口地址位帶映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //GPIOA輸出數(shù)據(jù)寄存器地址0x4001080C
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //GPIOB輸出數(shù)據(jù)寄存器地址0x40010C0C
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //GPIOC輸出數(shù)據(jù)寄存器地址0x4001100C
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //GPIOD輸出數(shù)據(jù)寄存器地址0x4001140C
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //GPIOE輸出數(shù)據(jù)寄存器地址0x4001180C
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //GPIOF輸出數(shù)據(jù)寄存器地址0x40011A0C
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //GPIOG輸出數(shù)據(jù)寄存器地址0x40011E0C

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //GPIOA輸入數(shù)據(jù)寄存器地址0x40010808
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //GPIOB輸入數(shù)據(jù)寄存器地址0x40010C08
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //GPIOC輸入數(shù)據(jù)寄存器地址0x40011008
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //GPIOD輸入數(shù)據(jù)寄存器地址0x40011408
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //GPIOE輸入數(shù)據(jù)寄存器地址0x40011808
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //GPIOF輸入數(shù)據(jù)寄存器地址0x40011A08
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //GPIOG輸入數(shù)據(jù)寄存器地址0x40011E08

//單個IO口位帶操作
#define PA_OUT(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //PAx輸出
#define PA_IN(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //PAx輸入

#define PB_OUT(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //PBx輸出
#define PB_IN(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //PBx輸入

#define PC_OUT(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //PCx輸出
#define PC_IN(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //PCx輸入

#define PD_OUT(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //PDx輸出
#define PD_IN(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //PDx輸入

#define PE_OUT(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //PEx輸出
#define PE_IN(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //PEx輸入

#define PF_OUT(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //PFx輸出
#define PF_IN(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //PFx輸入

#define PG_OUT(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //PGx輸出
#define PG_IN(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //PGx輸入

void delay_us(u16 us);
void delay_ms(u16 ms);

#endif

二、程序講解

特別注意程序校驗的那一點的算法,原數(shù)與取反后的數(shù)進行異或等于0xFF,說明次數(shù)正確,否則就清零開機次數(shù)。

三、注意事項

1、為了方便I2C.c的管腳操作,在config.h中加入了位帶操作

2、I2C中的延時采用的是config.c中的__ASM ("nop");延時方法

3、I2C中先設(shè)置引腳輸出,再初始化。

    GPIO_SetBits(GPIOB, GPIO_Pin_6|GPIO_Pin_7);           //SCL和SDA初始輸出高電平(先設(shè)置引腳電平可以避免IO初始化過程中可能產(chǎn)生的毛刺)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;  //選擇SCL和SDA引腳
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;      //選擇開漏輸出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;     //輸出速率10MHz
    GPIO_Init(GPIOB, &GPIO_InitStructure);

因為你想啊,上電后為浮空輸入,然后又有上拉電阻存在,自然變成高電平。到了I2C初始化這一點,因為數(shù)據(jù)輸出寄存器復(fù)位默認值為0,如果先初始化再設(shè)置引腳輸出電平,就會先輸出低(初始化為開漏輸出),然后再設(shè)置引腳輸出電平高,自然有了 高 -> 低 -> 高的狀態(tài),當(dāng)然會產(chǎn)生毛刺,所以這里先設(shè)置引腳電平,再初始化。

其實不這樣,事也不大。

聲明:本內(nèi)容為作者獨立觀點,不代表電子星球立場。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯的朋友,別忘了一鍵三連哦!
贊 161
收藏 161
關(guān)注 431
成為作者 賺取收益
全部留言
0/200
  • dy-i2UfRuvP 2021-05-19 13:17
    什么時候更新
    回復(fù)
  • dy-iipPZRPN 2021-05-13 22:39
    學(xué)習(xí)了
    回復(fù)
  • dy-3EbVR6Ei 2021-05-13 22:27
    講的真好!
    回復(fù)
  • dy-Xq2JxpfN 2021-05-13 22:13
    不亞于看了一篇高質(zhì)量論文
    回復(fù)
  • dy-9g42stbW 2021-05-13 21:57
    不亞于看了一篇高質(zhì)量論文
    回復(fù)
  • dy-mLj7kl5v 2021-05-13 20:33
    圍觀學(xué)習(xí)
    回復(fù)
  • dy-apcih3c1 2021-05-13 20:12
    圍觀學(xué)習(xí)
    回復(fù)
  • dy-k78ZHtFD 2021-05-13 20:02
    思路清晰,受益匪淺
    回復(fù)
  • dy-nAWdnPGS 2021-05-13 18:50
    思路清晰,受益匪淺
    回復(fù)
  • dy-jqGVYqsF 2021-05-13 16:07
    學(xué)習(xí)了
    回復(fù)
  • dy-VIQ9auhf 2021-05-13 14:54
    期待繼續(xù)
    回復(fù)
  • dy-7mura2gg 2021-05-13 14:44
    比論文強一萬倍
    回復(fù)
  • dy-YN3DYTeH 2021-05-13 14:34
    思路清晰,受益匪淺
    回復(fù)
  • dy-9hjGevyn 2021-05-13 13:33
    大開眼界,真是好文
    回復(fù)
  • dy-H1WY5jXH 2021-05-13 13:17
    圍觀學(xué)習(xí)
    回復(fù)
  • dy-wVQjSHHX 2021-05-13 12:59
    比論文強一萬倍
    回復(fù)
  • dy-88VlYaFf 2021-05-12 15:35
    圍觀學(xué)習(xí)
    回復(fù)
  • dy-9QTV6UZW 2021-05-12 15:23
    不亞于看了一篇高質(zhì)量論文
    回復(fù)
  • dy-WYS5BCmB 2021-05-12 15:10
    期待繼續(xù)
    回復(fù)
  • dy-24clvK2q 2021-05-12 14:57
    期待繼續(xù)
    回復(fù)