【STM32嵌入式蓝桥杯】11 M24C02 EEPOM存储芯片 软件IIC协议

CubeMX配置

只要配置PB6和PB7为默认输出模式就好

软件上,需要移植比赛提供的两个IIC源代码文件:

代码:

uint8_t Eeprom_Read(uint8_t addr)
{
	uint8_t dat;
	I2CStart();
	I2CSendByte(0xa0); /*0101 A1A2A3 R/W片选AT24C02,0为写入eeprom*/
	I2CWaitAck();//等待应答
	I2CSendByte(addr); 
	I2CWaitAck();//等待应答
	I2CStop();
	
	I2CStart();
	I2CSendByte(0xa1); /*1为读eeprom*/
	I2CWaitAck();//等待应答 
	dat=I2CReceiveByte();  /*读出指定的位置*/
	I2CWaitAck();//等待应答
	I2CStop();
	return dat;
}

void Eeprom_Write(uint8_t addr ,uint8_t dat)
{
	I2CStart();
	I2CSendByte(0xa0); /*0101 A1A2A3 R/W片选AT24C02,0为写入eeprom*/
	I2CWaitAck();//等待应答
	I2CSendByte(addr); 
	I2CWaitAck();//等待应答

	I2CSendByte(dat); 
	I2CWaitAck();//等待应答
	I2CStop();	
}
#include "app.h"
#include "lcd.h"
#include "stdio.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "stdbool.h"  /*包含布尔类型定义*/
#include <stdio.h>
#include "math.h"
#include "adc.h"
#include "dac.h"
#include "rtc.h"
#include "i2c_hal.h"
/********************************************************************************************/
uint8_t dis=0;  /*利用这个标志,上电之后运行完对应的初始化后*/
/********************************************************************************************/
/********************************************************************************************/
Key keys[4]={0,0,0,0,0};         /*按键的结构体变量初始化*/
/********************************************************************************************/
/********************************************************************************************/
char text[30];                   /*用来存放转换后的变量*/
/********************************************************************************************/
/********************************************************************************************/
//USART  串口相关的全局变量
uint8_t usart1_rx_buffer[USART_DMA_RX_BUFFER_MAXIMUM]; //串口1的DMA接收缓冲区
uint8_t usart1_rx_flag = 0; //DMA接收成功标志 0:未接收到    1:接收到等待处理
uint16_t usart1_rx_len = 0; //DMA一次空闲中断接收到的数据长度
/*******************************************************************************************/

/*******************************************************************************************/
//FRQ 输入捕获相关的全局变量
uint8_t testFinish=0;         /*捕获完成标志*/
uint8_t testFinish2=0;		  /*捕获完成标志*/
uint16_t J10_Frq=0,J9_Frq=0;  /*捕获后转换的测量频率,J9\J10是连接的跳帽*/
float J10_Duty=0,J9_Duty=0;   /*捕获后转换的占空比,J9\J10是连接的跳帽*/
/*******************************************************************************************/

/*-------------------------------------------------------------------------------------
 * 函数名称:Main_App
 * 函数功能:放在主函数的while(1)循环里,这样以后生成就不用动其他文件了。直接在这里操作
---------------------------------------------------------------------------------------*/
void Main_App(void)  /*主函数while(1)*/
{	

	if(dis) /*循环的业务代码放这里*/
	{
		
		
		LCD_SetTextColor(Black);
		LCD_SetBackColor(White);
		
		LCD_SetTextColor(Black);
		LCD_SetBackColor(White);

		sprintf(text,"EEPROM_DATA:%d    ",Eeprom_Read(0)); /*在0位置读出数据*/
		LCD_DisplayStringLine(Line3,(uint8_t *)text);
		
	}
	else  /*只进来一次,放外设的初始化*/
	{
		Led_PIN_SET();
		LCD_Init();
		LCD_Clear(White);	

		Eeprom_Write(0,24); /*在0位置写入24*/
		HAL_Delay(10);
		dis=1;
	}
	
}
/***********************************************************************************************************************
EEPROM  BEGIN
**********************************************************************************************************************/
uint8_t Eeprom_Read(uint8_t addr)
{
	uint8_t dat;
	I2CStart();
	I2CSendByte(0xa0); /*0101 A1A2A3 R/W片选AT24C02,0为写入eeprom*/
	I2CWaitAck();//等待应答
	I2CSendByte(addr); 
	I2CWaitAck();//等待应答
	I2CStop();
	
	I2CStart();
	I2CSendByte(0xa1); /*1为读eeprom*/
	I2CWaitAck();//等待应答 
	dat=I2CReceiveByte();  /*读出指定的位置*/
	I2CWaitAck();//等待应答
	I2CStop();
	return dat;
}

void Eeprom_Write(uint8_t addr ,uint8_t dat)
{
	I2CStart();
	I2CSendByte(0xa0); /*0101 A1A2A3 R/W片选AT24C02,0为写入eeprom*/
	I2CWaitAck();//等待应答
	I2CSendByte(addr); 
	I2CWaitAck();//等待应答

	I2CSendByte(dat); 
	I2CWaitAck();//等待应答
	I2CStop();	
}
/***********************************************************************************************************************
EEPROM  BEGIN
**********************************************************************************************************************/



/***********************************************************************************************************************
RTC  BEGIN
**********************************************************************************************************************/
/*定义时间日期结构体变量*/
//RTC_TimeTypeDef rtcTime;  /*存储时间结构体变量*/
//RTC_DateTypeDef rtcDate;  /*存储日期结构体变量*/
//读取时间
//HAL_RTC_GetTime(&hrtc,&rtcTime,FORMAT_BIN);  /*更新时间*/	
//HAL_RTC_GetDate(&hrtc,&rtcDate,FORMAT_BIN);  /*更新日期*/
//写入新时间
//rtcDate.Year=24;
//rtcDate.Month=12;
//rtcDate.Date=31;
//rtcTime.Hours=23;
//rtcTime.Minutes=59;
//rtcTime.Seconds=50;
//HAL_RTC_SetDate(&hrtc, &rtcDate, RTC_FORMAT_BIN);  /*写入时间*/
//HAL_RTC_SetTime(&hrtc, &rtcTime, RTC_FORMAT_BIN);  /*写入日期*/
/***********************************************************************************************************************
RTC  BEGIN
**********************************************************************************************************************/

/***********************************************************************************************************************
DAC  BEGIN
**********************************************************************************************************************/
//HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);			/*开启dac通道一*/
//HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1,DAC_ALIGN_12B_R, (4095*M_T.Volt/3.3f));/*DAC,赋初值*/
/***********************************************************************************************************************
DAC  BEGIN
**********************************************************************************************************************/


/***********************************************************************************************************************
ADC  BEGIN
**********************************************************************************************************************/
double Get_ADValue(ADC_HandleTypeDef *Pin)
{
	uint16_t ad_val=0;
	HAL_ADC_Start(Pin);
	ad_val=HAL_ADC_GetValue(Pin);
	//HAL_ADC_Stop(Pin);
	return ad_val*3.3/4096;
}
/***********************************************************************************************************************
ADC  END
**********************************************************************************************************************/

/***********************************************************************************************************************
PWM  BEGIN
**********************************************************************************************************************/
/*设置对应的频率和占空比输出*/
//公式:频率=80 000 000 / PSC / ARR  需要配置PSC ARR
//占空比(%) =  CCR1  / (ARR+1)   
//__HAL_TIM_SET_COMPARE(&htim17,TIM_CHANNEL_1,CCR1); /*把传参进来的PWM值送给定时的channe1通道*/
void Set_PWM(uint16_t Freq,uint16_t Duty)
{ 
	uint32_t PSCArr,psc,arr; //PSCArr=psc*arr
	PSCArr = 80000000/Freq;
	psc=sqrt(PSCArr);  /*开方,需要包含math.h*/
	arr = PSCArr/psc; 
	
	
	HAL_TIM_PWM_Stop(&htim17,TIM_CHANNEL_1);  /*停止PWM输出*/
	TIM17->PSC=psc-1;  /*分频系数*/
	TIM17->ARR=arr-1;  /*计数值*/
	TIM17->CCR1=Duty/100.0*arr; /*占空比*/
	HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);/*重新开启PWM*/
}
/***********************************************************************************************************************
PWM  BEGIN
**********************************************************************************************************************/

/***********************************************************************************************************************
FRQ  BEGIN
**********************************************************************************************************************/
/*定时器输入捕获中断回调*/
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)   
{
	static uint16_t cycle=0,cycle2=0;    /*捕获的电平周期计数*/
	static float dutyCnt=0,dutyCnt2=0;   /*捕获的占空比计数*/
	
	if(htim==&htim3)       /*J9口*/
	{
		if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_2)			//占空比计数值
		{
			dutyCnt2=TIM3->CCR2;     
		}
		else if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)	//周期计数值
		{
			cycle2=TIM3->CCR1;
			J9_Frq=1000000/cycle2;				//转换成频率,因为分频系数设成了80,所以这里是1 000 000Hz,
			J9_Duty=100*dutyCnt2/cycle2;	    //占空比
			testFinish=1;
		}
	}
	else if(htim==&htim2)
	{
		dutyCnt=TIM2->CCR2;
		cycle=TIM2->CCR1;
		J10_Frq=1000000/cycle;				//频率
		J10_Duty=100*dutyCnt/cycle;	        //占空比
		testFinish2=1;
	}
}

/***********************************************************************************************************************
FRQ  END
**********************************************************************************************************************/

/***********************************************************************************************************************
USART  BEGIN
**********************************************************************************************************************/
/*printf函数重定义*/
int fputc(int ch,FILE *f)
{
	HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,10);
	return ch;
}


/*串口中断回调函数*/
void My_UARTEx_RxEventCallback(UART_HandleTypeDef *huart)
{
	if (huart->Instance == USART1) //如果是串口1
	{
		usart1_rx_len = USART_DMA_RX_BUFFER_MAXIMUM - (__HAL_DMA_GET_COUNTER(&hdma_usart1_rx)); //接收个数等于接收缓冲区总大小减剩余计数
		usart1_rx_buffer[usart1_rx_len]	='\0'; //清除上次缓存的数据
		if(usart1_rx_len!=0)
			usart1_rx_flag = 1; //标志已经成功接收到一包等待处理
		HAL_UART_Receive_DMA(&huart1,usart1_rx_buffer,USART_DMA_RX_BUFFER_MAXIMUM);  //启动DMA接收,UART1_RX_BUF:数据接收缓冲
	}

}

/***********************************************************************************************************************
USART  END
**********************************************************************************************************************/


/***********************************************************************************************************************
KEY  BEGIN
**********************************************************************************************************************/
/*----------------------------------------------------------------------------------------------------
*函数名称:KEY_Scan(uint8_t mode)
*函数功能:按键处理函数,状态机,假设同时只有一个按键按下,无论长按还是短按都只判断按下,记作一次
 这个代码只能一次性判断一个按键按下,无法对同一时刻多个按键按下进行判断
*输    入:mode  1:按键连按; 2:按键只读取一次
*返 回 值:按键键值
-----------------------------------------------------------------------------------------------------*/
uint8_t KEY_Scan(void)
{	 
	static uint8_t key_up=1;//按键按松开的标志
	  
	if(key_up && (B1==0 || B2==0 || B3==0 || B4==0))  //检测到有按键按下
	{
		HAL_Delay(10);//去抖动 
		key_up=0;            
		if(B1==0)       return 1; //1
		else if(B2==0)  return 2; //2
		else if(B3==0)  return 3; //3
		else if(B4==0)  return 4; //4
	}
	else if(B1==1 && B2==1 && B3==1 && B4==1) key_up=1; 	    
 	return 0;// 没有按键按下
}




/*这里放在定时器中断里*/
/*----------------------------------------------------------------------------------------------------
*函数名称:void key_scan(void)e)
*函数功能:按键处理函数,支持长按(keys[i].sflag =1)
*输    入:
*返 回 值:
*修 改 人:ZXP 2023/12/27
-----------------------------------------------------------------------------------------------------*/
void key_scan(void)
{
	static uint8_t i=0;
    /*按键状态读取*/
    keys[0].state =  B1;
    keys[1].state =  B2;
    keys[2].state =  B3;
    keys[3].state =  B4;
	
	/*支持多个按键同时按下*/
	for(i=0;i<4;i++)
	{
		switch(keys[i].keystate) /*用来消抖的,定时器6是每10ms进来一次,第一次进来这个为0,2次进来才开读取按键键值始*/
		{
			case 0:
					if( !keys[i].state)
					{
						keys[i].keystate =1; /*10ms后进入case 1*/
						keys[i].keytime = 0;
					}
					break;
			case 1:
					 if(!keys[i].state)
					 {
						 keys[i].keystate =2; /*10ms后进入case 2*/
						 
					 }
					 else 
						 keys[i].keystate = 0; /*表示没有按键按下,消抖了*/
					break;
			case 2:
					if(!keys[i].state)         /*松手检测,这里表示没有松手*/
					{
//						if(keys[i].keytime < 1000)  /*小于800才加,避免溢出然后置零*/
						keys[i].keytime+=10;   /*按键按下的时间累加,一次10ms*/
						if(keys[i].keytime > 800) /*800ms*/
						{
							keys[i].lflag = 1; /*表示长按*/
//							keys[i].sflag = 0; /*短按清零*/
						}						
					}
					else    /*表示松手了*/
					{
						if (keys[i].keytime <= 800)
						{
							keys[i].sflag = 1; /*表示短按*/
							keys[i].lflag = 0; /*功能函数里来判断这两个变量状态*/
						}
						keys[i].keytime = 0;   /**/
						keys[i].keystate = 0;  
						keys[i].lflag = 0; /*长按松开清零,短按功能函数里清零*/						
					}    
					break;
				default:
					break;
		}
	}
}
/***********************************************************************************************************************
KEY  END
**********************************************************************************************************************/


/***********************************************************************************************************************
TIME  BEGIN
**********************************************************************************************************************/
/*中断回调函数*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

	/*定时器6*/
	if(htim->Instance==TIM6) 
	{
		key_scan();
	}
}
/***********************************************************************************************************************
TIME  END
**********************************************************************************************************************/


/***********************************************************************************************************************
LCD  BEGIN
**********************************************************************************************************************/
void My_LCD_DisplayStringLine(uint8_t Line, uint16_t Column,uint8_t *ptr) /*自己修改的字符串显示*/
{
	u16 refcolumn = Column;//319;

	while ((*ptr != 0))	  //20
	{
		LCD_DisplayChar(Line, refcolumn, *ptr);
		refcolumn -= 16;
		ptr++;
	}
}
//举例
//char text[30];                   /*用来存放转换后的变量*/
//LCD_SetTextColor(Black);
//LCD_SetBackColor(White);

//LCD_DisplayStringLine(Line1,(uint8_t *)"   Data       ");
///*显示日期*/
//sprintf(text,"   date:20%d-%02d-%02d    ",rtcDate.Year,rtcDate.Month,rtcDate.Date);
//LCD_DisplayStringLine(Line3,(uint8_t *)text);
///*显示时间*/
//sprintf(text,"   time:%02d:%02d:%02d    ",rtcTime.Hours,rtcTime.Minutes,rtcTime.Seconds);
//LCD_DisplayStringLine(Line5,(uint8_t *)text);

/***********************************************************************************************************************
LCD  END
**********************************************************************************************************************/


/***********************************************************************************************************************
LED  BEGIN
************************************************************************************************************************/
uint16_t GPIOC_ODR=0xFF00;  //两个FF对应的高位PC8~15
/*----------------------------------------------------------------------------------------------------
*函数名称:Led_PIN_SET()
*函数功能:流水灯全部置高电平
*输    入:无
*返 回 值:无
-----------------------------------------------------------------------------------------------------*/
void Led_PIN_SET(void)
{
	
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOC,0xff<<8,GPIO_PIN_SET);
	GPIOC_ODR=GPIOC->ODR;      //记录本次流水灯的点亮状态
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}


/*----------------------------------------------------------------------------------------------------
*函数名称:LedCtrl(uint8_t ds,uint8_t LED_State)
*函数功能:点亮和熄灭指定的LED灯
*输    入:ds:1~8,LED的位置,LED_State:0/1;0:指定的灯熄灭,1:指定的灯点亮
*返 回 值:无
*修 改 人:ZXP 2023/12/28 10:41
-----------------------------------------------------------------------------------------------------*/
void LedCtrl(uint8_t ds,uint8_t LED_State)
{
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);//开启锁存器的数据直通
	if(LED_State)
	{
		GPIOC->ODR |=0xFF00;   		            //熄灭所有led
		GPIOC->ODR &= ~(1<<(ds+7) | ~GPIOC_ODR); //保持上一个灯的状态,加7是为了移到高8位
		GPIOC_ODR=GPIOC->ODR;                    //记录本次流水灯的点亮状态
	}
	else if(!LED_State)
	{
		GPIOC->ODR |= (1<<(ds+7) | GPIOC_ODR); //熄灭指定的灯,或运算,1,加7是为了移到高8位
		GPIOC_ODR=GPIOC->ODR;                  //记录本次流水灯的点亮状态
	}
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);//锁存	
}
/***********************************************************************************************************************
LED  END
************************************************************************************************************************/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值