STM32驅動SPI接口EEPROM,AT25010、AT25020、AT25040

一、源代碼

void eeprom_init()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	 SPI_InitTypeDef  SPI_InitStructure;
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );//PORTB時鐘使能 

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12;  // PB12 推輓 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //推輓輸出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_SetBits(GPIOB,GPIO_Pin_11|GPIO_Pin_12);



	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOB, ENABLE );//PORTB時鐘使能 
	RCC_APB1PeriphClockCmd(	RCC_APB1Periph_SPI2,  ENABLE );//SPI2時鐘使能 	
 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //PB13/14/15複用推輓輸出 
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB

 	GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);  //PB13/14/15上拉

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //設置SPI單向或者雙向的數據模式:SPI設置爲雙線雙向全雙工
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//設置SPI工作模式:設置爲主SPI
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//設置SPI的數據大小:SPI發送接收8位幀結構
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//串行同步時鐘的空閒狀態爲高電平
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//串行同步時鐘的第二個跳變沿(上升或下降)數據被採樣
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信號由硬件(NSS管腳)還是軟件(使用SSI位)管理:內部NSS信號有SSI位控制
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;		//定義波特率預分頻的值:波特率預分頻值爲256
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定數據傳輸從MSB位還是LSB位開始:數據傳輸從MSB位開始
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值計算的多項式
	SPI_Init(SPI2, &SPI_InitStructure);  //根據SPI_InitStruct中指定的參數初始化外設SPIx寄存器
 
	SPI_Cmd(SPI2, ENABLE); //使能SPI外設
	
	eeprom_read_write_byte(0xff);//啓動傳輸		
}
//SPI 速度設置函數
//SpeedSet:
//SPI_BaudRatePrescaler_2   2分頻   
//SPI_BaudRatePrescaler_8   8分頻   
//SPI_BaudRatePrescaler_16  16分頻  
//SPI_BaudRatePrescaler_256 256分頻 
  
void eeprom_set_speed(u8 SPI_BaudRatePrescaler)
{
  assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
	SPI2->CR1&=0XFFC7;
	SPI2->CR1|=SPI_BaudRatePrescaler;	//設置SPI2速度 
	SPI_Cmd(SPI2,ENABLE); 

} 
//SPIx 讀寫一個字節
//TxData:要寫入的字節
//返回值:讀取到的字節
u8 eeprom_read_write_byte(u8 TxData)
{		
	u8 retry=0;				 	
	while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //檢查指定的SPI標誌位設置與否:發送緩存空標誌位
		{
		retry++;
		if(retry>200)return 0;
		}			  
	SPI_I2S_SendData(SPI2, TxData); //通過外設SPIx發送一個數據
	retry=0;

	while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) //檢查指定的SPI標誌位設置與否:接受緩存非空標誌位
		{
		retry++;
		if(retry>200)return 0;
		}	  						    
	return SPI_I2S_ReceiveData(SPI2); //返回通過SPIx最近接收的數據					    
}
//==============================================================================
// 描述: 在AT25讀狀態寄存器
// 輸入: 無
// 返回: unsigned char dat 狀態寄存器數據
//==============================================================================


u8 eeprom_read_sr(void)
{ 
	u8 dat; 
	eeprom_cs=0; 
	eeprom_read_write_byte(RDSR);        //  定入指令0x05
	dat = eeprom_read_write_byte(0xff);       //  讀回數據
	eeprom_cs=1;
	return  dat;
}

//==============================================================================
// 描述: 向AT25寫入一個數據
// 輸入: unsigned char Dat 字符數據
//       unsigned int addr 寫入的地址
// 返回: 無
//==============================================================================
void eeprom_write_byte(u16 addr,u8 Dat)
{ 
	unsigned char Add; 
	while(eeprom_read_sr()&RDY);                   // 讀狀態寄存器
	
	eeprom_cs=0;
	eeprom_read_write_byte(WREN);                           // 寫使能鎖存
	eeprom_cs=1;
	
	eeprom_cs=0;                                  // 芯片使能 
	// 寫入寫操作指令 
	if(addr>0x00ff)
		eeprom_read_write_byte((WRITE|0x08));           // 地址大於255
	else
		eeprom_read_write_byte(WRITE);                  // 地址小於255

	// 寫入地址
	Add = (unsigned char)(addr & 0xff);             // 將地址換成8位
	eeprom_read_write_byte(Add); 

	// 寫入數據
	eeprom_read_write_byte(Dat);
	eeprom_cs=1;                                // 芯片關閉    
}
//==============================================================================
// 描述: 在AT25讀一個字節操作
// 輸入: 無
// 返回: unsigned char dat 讀出一個字符數據
//==============================================================================
u8 eeprom_read_byte(u16 addr)
{ 
	u8 dat,add;
	while(eeprom_read_sr()&RDY);                   // 讀狀態寄存器  
	eeprom_cs=0;
	// 寫入寫操作指令 
	if(addr>0x00ff)
		eeprom_read_write_byte((READ | 0x08));         // 地址大於255
	else
		eeprom_read_write_byte(READ);                  // 地址小於255

	// 寫入地址
	add = (unsigned char)(addr & 0xff);             // 將地址換成8位
	eeprom_read_write_byte(add); 

	// 讀出一個數據
	dat=eeprom_read_write_byte(0xff);
	eeprom_cs=1;
	return dat;
}
//==============================================================================
// 描述: 向AT25連續寫入數據
// 輸入: unsigned char *PC 寫入數據指針
//       unsigned int count 寫入數量計數  
//       unsigned int SatAddr 寫入起始地址
// 返回: 無
//==============================================================================
void eeprom_write_buf(u16 startAddr,u8 *buf,u16 count)
{ 
	u8 Add; 
	u16 i;
	while(eeprom_read_sr()&RDY);                   // 讀狀態寄存器

	eeprom_cs=0;
	eeprom_read_write_byte(WREN);                           // 寫使能鎖存
	eeprom_cs=1;
	eeprom_cs=0;
	// 寫入寫操作指令 
	if(startAddr>0x00ff)
		eeprom_read_write_byte((WRITE|0x08));           // 地址大於255
	else
		eeprom_read_write_byte(WRITE);                  // 地址小於255

	// 寫入地址
	Add = (unsigned char)(startAddr & 0xff);             // 將地址換成8位
	eeprom_read_write_byte(Add); 

	for(i=0;i<count;i++)// 寫入數據
	{ 
		eeprom_read_write_byte(*buf++);
	}
	eeprom_cs=1;                                 // 芯片關閉    
}
//==============================================================================
// 描述: 在AT25連續讀數據
// 輸入: unsigned char *PC 讀出數據指針
//       unsigned int count 讀出數量計數  
//       unsigned int SatAddr 讀出起始地址
// 返回: 無
//==============================================================================
void eeprom_read_buf(u16 startAddr,u8 *buf,u16 count)
{ 
	unsigned char Add; 
	unsigned int i;
	while(eeprom_read_sr()&RDY);                   // 讀狀態寄存器  
	eeprom_cs=0;
	// 寫入寫操作指令 
	if(startAddr>0x00ff)
		eeprom_read_write_byte((READ | 0x08));         // 地址大於255
	else
		eeprom_read_write_byte(READ);                  // 地址小於255

	// 寫入地址
	Add = (unsigned char)(startAddr & 0xff);             // 將地址換成8位
	eeprom_read_write_byte(Add); 

	// 讀出n個數據
	for(i=0;i<count;i++)
	{
		*buf++ = eeprom_read_write_byte(0xff);
	}
	eeprom_cs=1;
}

二、測試

int main(void)
{	
	u8 buf[5]={0x01,0x02,0x03,0x04,0x05},i;
	uart_init(115200);
	delay_init();	
	program_led_init();	
	
	eeprom_wp=1;
	eeprom_init();
	eeprom_write_buf(0x0000,buf,sizeof(buf));
//	eeprom_write_byte(0x0000,0x08);
	memset(buf,0x00,sizeof(buf));
	eeprom_wp=0;
	while(1)
	{	
		
		eeprom_read_buf(0x0000,buf,sizeof(buf));
	//	buf[0]=eeprom_read_byte(0x0001);
		for(i=0;i<sizeof(buf);i++)
			printf("0x%02x ",buf[i]);
		printf("\r\n");
		memset(buf,0x00,sizeof(buf));
		
		program_led_data(0x10,0x10,0x10);
		delay_ms(500);

		program_led_data(0x00,0x00,0x00);
		delay_ms(500);	
		
		
	}
}

三、原理圖
暫留

源代碼鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章