本帖最后由 怀揣少年梦 于 2023-11-10 11:44 编辑
一、开发板上硬件设计
CW32L031CxTx StartKit评估板上板载一颗型号为CW24C02AD的EEPROM,EEPROM适用于保存数据量比较小的场景,并且可靠性比较高。
先看一下CW24C02AD的数据手册,可以看到该EEPROM只有2Kbit,也就是256字节(这是EEPROM中容量最小的芯片),每页8个字节,一共32页。工作电压1.7-5.5V;允许页面局部写入;I2C 时钟频率为 1MHz (5V,3V),400 KHz (1.7V);擦写寿命:100 万次;数据保持时间: 20年;
从评估板的原理图来看,EEPROM的A2\A1\A0三个引脚接地,说明读写EEPROM的地址为A0;
二、软件设计
使用GPIO口模拟I2C读写EEPROM。
具体代码如下:
1).c代码
#include "eeprom.h"
#define I2C_DIR_TRANSMIT 0x00
#define I2C_DIR_RECEIVE 0x01
#define I2C_ACK_TIMEOUT 64
#define I2C_SCL_HIGH() GPIO_WritePin(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_PIN, GPIO_Pin_SET)
#define I2C_SCL_LOW() GPIO_WritePin(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_PIN, GPIO_Pin_RESET)
#define I2C_SDA_HIGH() GPIO_WritePin(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_PIN, GPIO_Pin_SET)
#define I2C_SDA_LOW() GPIO_WritePin(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_PIN, GPIO_Pin_RESET)
#define I2C_SDA_READ GPIO_ReadPin(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_PIN)
#define I2C_DALEY_US 5
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] i2c address direction
*/
void i2c_config(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* i2c gpio clock enable */
__RCC_GPIOB_CLK_ENABLE();
/* gpio configuration */
GPIO_InitStruct.IT = GPIO_IT_NONE;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
/* configure i2c pins: scl */
GPIO_InitStruct.Pins = I2Cx_SCL_PIN;
GPIO_Init(I2Cx_SCL_GPIO_PORT, &GPIO_InitStruct);
/* configure i2c pins: sda */
GPIO_InitStruct.Pins = I2Cx_SDA_PIN;
GPIO_Init(I2Cx_SDA_GPIO_PORT, &GPIO_InitStruct);
I2C_SDA_HIGH();
I2C_SCL_HIGH();
}
/**
* @brief used to set the i2c clock frequency.
* @param none.
* @retval none.
*/
void i2c_delay(void)
{
uint8_t i = 0;
uint8_t j = 48;
for (i = 0; i< I2C_DALEY_US; i++) {
while(j--);
}
}
/**
* @brief 循环延时
*
* @param nCount
*/
void Delay(__IO uint16_t nCount)
{
/* Decrement nCount value */
while (nCount != 0)
{
nCount--;
}
}
/**
* @brief used to generate start conditions.
* @param none.
* @retval none.
*/
void i2c_start(void)
{
i2c_delay();
I2C_SDA_HIGH();
I2C_SCL_HIGH();
i2c_delay();
I2C_SDA_LOW();
i2c_delay();
I2C_SCL_LOW();
i2c_delay();
}
/**
* @brief used to generate stop conditions.
* @param none.
* @retval none.
*/
void i2c_stop(void)
{
I2C_SCL_LOW();
I2C_SDA_LOW();
i2c_delay();
I2C_SCL_HIGH();
i2c_delay();
I2C_SDA_HIGH();
i2c_delay();
}
/**
* @brief used to generate ack conditions.
* @param none.
* @retval none.
*/
void i2c_ack(void)
{
I2C_SCL_LOW();
I2C_SDA_LOW();
i2c_delay();
I2C_SCL_HIGH();
i2c_delay();
I2C_SCL_LOW();
i2c_delay();
}
/**
* @brief used to generate nack conditions.
* @param none.
* @retval none.
*/
void i2c_no_ack(void)
{
I2C_SCL_LOW();
I2C_SDA_HIGH();
i2c_delay();
I2C_SCL_HIGH();
i2c_delay();
I2C_SCL_LOW();
i2c_delay();
}
/**
* @brief used to wait ack conditions.
* @param none.
* @retval ack receive status.
* - 1: no ack received.
* - 0: ack received.
*/
uint8_t i2c_wait_ack(uint8_t timeout)
{
I2C_SCL_LOW();
I2C_SDA_HIGH();
i2c_delay();
while(timeout)
{
if (I2C_SDA_READ == 0)
{
I2C_SCL_HIGH();
i2c_delay();
I2C_SCL_LOW();
return 0;
}
i2c_delay();
timeout--;
}
return 1;
}
/**
* @brief send a byte.
* @param data: byte to be transmitted.
* @retval none.
*/
void i2c_send_byte(uint8_t data)
{
uint8_t i = 8;
I2C_SCL_LOW(); //
while (i--)
{
if (data & 0x80)
{
I2C_SDA_HIGH();
}
else
{
I2C_SDA_LOW();
}
i2c_delay();
I2C_SCL_HIGH();
i2c_delay();
I2C_SCL_LOW();
i2c_delay();
data <<= 1;
}
}
/**
* @brief receive a byte.
* @param data: byte to be received.
* @retval none.
*/
uint8_t i2c_receive_byte(void)
{
uint8_t i = 8;
uint8_t byte = 0;
I2C_SDA_HIGH();
I2C_SCL_LOW();
while (i--)
{
byte <<= 1;
I2C_SCL_HIGH();
i2c_delay();
byte |= I2C_SDA_READ;
I2C_SCL_LOW();
i2c_delay();
}
return byte;
}
uint8_t i2c_WriteByte(uint8_t I2C_Addr,uint8_t addr,uint8_t data)
{
i2c_start();
i2c_send_byte(I2C_Addr | I2C_DIR_TRANSMIT);; //
if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
{
i2c_stop();
return 1;
}
i2c_send_byte(addr); //
if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
{
i2c_stop();
printf("EEPROM %x \r\n",addr);
return 1;
}
i2c_send_byte(data);
if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
{
i2c_stop();
printf("EEPROM %x \r\n",data);
return 1;
}
i2c_stop(); //
Delay(0xffff);
Delay(0xffff);
Delay(0xffff);
printf("write ok\r\n");
return 0;
}
uint8_t i2c_ReadCurrentAddrByte(uint8_t I2C_Addr)
{
uint8_t data;
i2c_start();
i2c_send_byte(I2C_Addr | I2C_DIR_RECEIVE);; //锟斤拷锟酵从伙拷锟斤拷址
if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
{
i2c_stop();
return 1;
}
data = i2c_receive_byte();
i2c_no_ack();
i2c_stop(); //
printf("receive1 ok\r\n");
return data;
}
uint8_t i2c_ReadByte(uint8_t I2C_Addr,uint8_t addr)
{
uint8_t data;
i2c_start();
i2c_send_byte(I2C_Addr | I2C_DIR_TRANSMIT);; //
if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
{
i2c_stop();
return 1;
}
i2c_send_byte((uint8_t)addr); //
if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
{
i2c_stop();
printf("EEPROM %x \r\n",addr);
return 1;
}
i2c_start();
i2c_send_byte(I2C_Addr | I2C_DIR_RECEIVE);; //
if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
{
i2c_stop();
printf("EEPROM %x \r\n",I2C_Addr);
return 1;
}
data = i2c_receive_byte();
i2c_no_ack();
i2c_stop(); //
printf("receive ok\r\n");
return data;
}
uint8_t i2c_ReadMultByte(uint8_t I2C_Addr,uint16_t addr,uint8_t length, uint8_t *pdata)
{
uint8_t i = 0;
i2c_start();
i2c_send_byte(I2C_Addr | I2C_DIR_TRANSMIT);; //
if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
{
i2c_stop();
return 1;
}
i2c_send_byte((uint8_t)addr); //
if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
{
i2c_stop();
printf("EEPROM %x \r\n",addr);
return 1;
}
i2c_start();
i2c_send_byte(I2C_Addr | I2C_DIR_RECEIVE);; //
if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
{
i2c_stop();
printf("EEPROM %x \r\n",I2C_Addr);
return 1;
}
for(i = 0; i< length; i++) {
pdata[i] = i2c_receive_byte();
if (i < (length - 1))
{
i2c_ack();
}
else
{
i2c_no_ack();
}
}
i2c_stop(); //
printf("mul receive ok\r\n");
return 0;
}
uint8_t i2c_WriteMultByte(uint8_t I2C_Addr,uint16_t addr,uint8_t length, uint8_t *pdata)
{
uint8_t i = 0;
i2c_start();
i2c_send_byte(I2C_Addr | I2C_DIR_TRANSMIT);; //
if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
{
i2c_stop();
return 1;
}
i2c_send_byte((uint8_t)addr); //
printf("addr high %x",(uint8_t)(addr));
if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
{
i2c_stop();
printf("EEPROM %x\r\n",addr);
return 1;
}
for(i = 0; i< length; i++) {
i2c_send_byte(pdata[i]);
if (i2c_wait_ack(I2C_ACK_TIMEOUT) == 1)
{
i2c_stop();
printf("EEPROM %d %x \r\n",i,addr);
return 1;
}
}
i2c_stop(); //
printf("write ok\r\n");
Delay(0xffff);
return 0;
}
2)、.h代码
#ifndef __EEPROM_H__
#define __EEPROM_H__
#include "..\inc\main.h"
#define I2Cx_SCL_PIN GPIO_PIN_6
#define I2Cx_SCL_GPIO_PORT CW_GPIOB
#define I2Cx_SDA_PIN GPIO_PIN_7
#define I2Cx_SDA_GPIO_PORT CW_GPIOB
/** @defgroup I2C_library_exported_functions
* @{
*/
void i2c_config(void);
void delay_us(uint32_t us);
void Delay(__IO uint16_t nCount);
uint8_t i2c_WriteByte(uint8_t I2C_Addr,uint8_t addr,uint8_t data);
uint8_t i2c_ReadCurrentAddrByte(uint8_t I2C_Addr);
uint8_t i2c_ReadByte(uint8_t I2C_Addr,uint8_t addr);
uint8_t i2c_ReadMultByte(uint8_t I2C_Addr,uint16_t addr,uint8_t length, uint8_t *pdata);
uint8_t i2c_WriteMultByte(uint8_t I2C_Addr,uint16_t addr,uint8_t length, uint8_t *pdata);
#endif
3)、测试主程序
#include "..\inc\main.h"
/******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
//UARTx
#define DEBUG_USARTx CW_UART1
#define DEBUG_USART_CLK RCC_APB2_PERIPH_UART1
#define DEBUG_USART_APBClkENx RCC_APBPeriphClk_Enable2
#define DEBUG_USART_BaudRate 9600
#define DEBUG_USART_UclkFreq 8000000
#define LED_GPIO_PORT CW_GPIOB
#define LED_GPIO_PINS GPIO_PIN_8 | GPIO_PIN_9
//UARTx GPIO
#define DEBUG_USART_GPIO_CLK RCC_AHB_PERIPH_GPIOA
#define DEBUG_USART_TX_GPIO_PORT CW_GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_PIN_8
#define DEBUG_USART_RX_GPIO_PORT CW_GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_PIN_9
//GPIO AF
#define DEBUG_USART_AFTX PA08_AFx_UART1TXD()
#define DEBUG_USART_AFRX PA09_AFx_UART1RXD()
/******************************************************************************
* Global variable definitions (declared in header file with 'extern')
******************************************************************************/
uint8_t test_data[] = {0x01,0x02,0x03};
uint8_t test_readdata[3] = {0x00};
/******************************************************************************
* Local type definitions ('typedef')
******************************************************************************/
/******************************************************************************
* Local function prototypes ('static')
******************************************************************************/
void RCC_Configuration(void);
void GPIO_Configuration(void);
void UART_Configuration(void);
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/******************************************************************************
* Local variable definitions ('static') *
******************************************************************************/
/******************************************************************************
* Local pre-processor symbols/macros ('#define')
******************************************************************************/
/*****************************************************************************
* Function implementation - global ('extern') and local ('static')
******************************************************************************/
/**
******************************************************************************
** \brief Main function of project
**
** \return uint32_t return value, if needed
**
******************************************************************************/
int32_t main(void)
{
//配置RCC
RCC_Configuration();
//配置GPIO
GPIO_Configuration();
//i2c_config();
//配置UART
UART_Configuration();
printf("\r\n use CW32L031 simulate I2C READ EEPROM Example\r\n");
while(1)
{
if (GPIO_ReadPin(CW_GPIOA, GPIO_PIN_1) == 0) {
i2c_WriteByte(0xA0,0x01,0x5A);
i2c_WriteMultByte(0xA0,0x05,3,test_data);
}
if (GPIO_ReadPin(CW_GPIOA, GPIO_PIN_2) == 0) {
printf("data:%x \r\n",i2c_ReadByte(0xA0,0x01));
i2c_ReadMultByte(0xA0,0x05,3,test_readdata);
for(int i = 0;i < 3; i++) {
printf("test_readdata[%d] = %x \r\n",i,test_readdata[i]);
}
}
GPIO_TogglePin(LED_GPIO_PORT, LED_GPIO_PINS);
Delay(0xFFFF);
}
}
/**
* @brief 配置RCC
*
*/
void RCC_Configuration(void)
{
//SYSCLK = HSI = 8MHz = HCLK = PCLK
RCC_HSI_Enable(RCC_HSIOSC_DIV6);
//外设时钟使能
RCC_AHBPeriphClk_Enable(DEBUG_USART_GPIO_CLK, ENABLE);
DEBUG_USART_APBClkENx(DEBUG_USART_CLK, ENABLE);
RCC_AHBPeriphClk_Enable(RCC_AHB_PERIPH_GPIOB,ENABLE);
__RCC_GPIOA_CLK_ENABLE();
}
/**
* @brief 配置GPIO
*
*/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
//UART TX RX 复用
DEBUG_USART_AFTX;
DEBUG_USART_AFRX;
GPIO_InitStructure.Pins = DEBUG_USART_TX_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pins = GPIO_PIN_1 | GPIO_PIN_2;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.Pins = DEBUG_USART_RX_GPIO_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT_PULLUP;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.IT = GPIO_IT_NONE;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pins = LED_GPIO_PINS;
GPIO_Init(LED_GPIO_PORT, &GPIO_InitStructure);
/* gpio configuration */
GPIO_InitStructure.IT = GPIO_IT_NONE;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD;
/* configure i2c pins: scl */
GPIO_InitStructure.Pins = I2Cx_SCL_PIN;
GPIO_Init(I2Cx_SCL_GPIO_PORT, &GPIO_InitStructure);
/* configure i2c pins: sda */
GPIO_InitStructure.Pins = I2Cx_SDA_PIN;
GPIO_Init(I2Cx_SDA_GPIO_PORT, &GPIO_InitStructure);
GPIO_WritePin(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_PIN, GPIO_Pin_SET);
GPIO_WritePin(I2Cx_SDA_GPIO_PORT, I2Cx_SDA_PIN, GPIO_Pin_SET);
}
/**
* @brief 配置UART
*
*/
void UART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure = {0};
USART_InitStructure.USART_BaudRate = DEBUG_USART_BaudRate;
USART_InitStructure.USART_Over = USART_Over_16;
USART_InitStructure.USART_Source = USART_Source_PCLK;
USART_InitStructure.USART_UclkFreq = DEBUG_USART_UclkFreq;
USART_InitStructure.USART_StartBit = USART_StartBit_FE;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(DEBUG_USARTx, &USART_InitStructure);
}
// KEIL
/**
* @brief Retargets the C library printf function to the USART.
*
*/
PUTCHAR_PROTOTYPE
{
USART_SendData_8bit(DEBUG_USARTx, (uint8_t)ch);
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return ch;
}
// IAR
size_t __write(int handle, const unsigned char * buffer, size_t size)
{
size_t nChars = 0;
if (buffer == 0)
{
/*
* This means that we should flush internal buffers. Since we
* don't we just return. (Remember, "handle" == -1 means that all
* handles should be flushed.)
*/
return 0;
}
for (/* Empty */; size != 0; --size)
{
USART_SendData_8bit(DEBUG_USARTx, *buffer++);
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
++nChars;
}
return nChars;
}
三、实际测试串口输出
单字节写入5a,单字节读出来也是5a;
多字节写入01 02 03;多字节读出来也是01 02 03
|
共1人点赞
|