APM32E030支持I2C通信,但本次我们使用GPIO模拟实现I2C与EEPROM进行通讯;
本次代码基于开发板:APM32E030R Micro-EVB
IO:SCL->PB6,SDA->PB7
模拟I2C驱动代码如下:
- /* IO操作 */
- #define IIC_SCL(x) do{ x ? \
- GPIO_SetBit(GPIOB, GPIO_PIN_6) : \
- GPIO_ClearBit(GPIOB, GPIO_PIN_6); \
- }while(0) /* SCL */
- #define IIC_SDA(x) do{ x ? \
- GPIO_SetBit(GPIOB, GPIO_PIN_7) : \
- GPIO_ClearBit(GPIOB, GPIO_PIN_7); \
- }while(0) /* SDA */
- #define IIC_READ_SDA GPIO_ReadInputBit(GPIOB, GPIO_PIN_7) /* 读取SDA */
- /**
- * @brief 初始化IIC
- * @param 无
- * @retval 无
- */
- void iic_init(void)
- {
- GPIO_Config_T gpioConfig;
-
- RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOB);
- RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
-
- /*
- * SCL -> PB6
- * SDA -> PB7
- */
- GPIO_ConfigStructInit(&gpioConfig);
- gpioConfig.pin = GPIO_PIN_6;
- gpioConfig.mode = GPIO_MODE_OUT;
- gpioConfig.outtype = GPIO_OUT_TYPE_PP;
- gpioConfig.speed = GPIO_SPEED_50MHz;
- gpioConfig.pupd = GPIO_PUPD_NO;
- GPIO_Config(GPIOB, &gpioConfig);
-
- gpioConfig.outtype = GPIO_OUT_TYPE_OD;
- gpioConfig.pin = GPIO_PIN_7;
- GPIO_Config(GPIOB, &gpioConfig);
-
- iic_stop(); /* 停止总线上所有设备 */
- }
- static void delay_us(uint32_t delay)
- {
- uint32_t us = 10 * delay;
-
- while (--us);
- }
- /**
- * @brief IIC延时函数,用于控制IIC读写速度
- * @param 无
- * @retval 无
- */
- static void iic_delay(void)
- {
- delay_us(2); /* 2us的延时, 读写速度在250Khz以内 */
- }
- /**
- * @brief 产生IIC起始信号
- * @param 无
- * @retval 无
- */
- void iic_start(void)
- {
- IIC_SDA(1);
- IIC_SCL(1);
- iic_delay();
- IIC_SDA(0); /* START信号: 当SCL为高时, SDA从高变成低, 表示起始信号 */
- iic_delay();
- IIC_SCL(0); /* 钳住I2C总线,准备发送或接收数据 */
- iic_delay();
- }
- /**
- * @brief 产生IIC停止信号
- * @param 无
- * @retval 无
- */
- void iic_stop(void)
- {
- IIC_SDA(0); /* STOP信号: 当SCL为高时, SDA从低变成高, 表示停止信号 */
- iic_delay();
- IIC_SCL(1);
- iic_delay();
- IIC_SDA(1); /* 发送I2C总线结束信号 */
- iic_delay();
- }
- /**
- * @brief 等待应答信号到来
- * @param 无
- * @retval 1,接收应答失败
- * 0,接收应答成功
- */
- uint8_t iic_wait_ack(void)
- {
- uint8_t waittime = 0;
- uint8_t rack = 0;
- IIC_SDA(1); /* 主机释放SDA线(此时外部器件可以拉低SDA线) */
- iic_delay();
- IIC_SCL(1); /* SCL=1, 此时从机可以返回ACK */
- iic_delay();
- while (IIC_READ_SDA) /* 等待应答 */
- {
- waittime++;
- if (waittime > 250)
- {
- iic_stop();
- rack = 1;
- break;
- }
- }
- IIC_SCL(0); /* SCL=0, 结束ACK检查 */
- iic_delay();
- return rack;
- }
- /**
- * @brief 产生ACK应答
- * @param 无
- * @retval 无
- */
- void iic_ack(void)
- {
- IIC_SDA(0); /* SCL 0 -> 1 时 SDA = 0,表示应答 */
- iic_delay();
- IIC_SCL(1); /* 产生一个时钟 */
- iic_delay();
- IIC_SCL(0);
- iic_delay();
- IIC_SDA(1); /* 主机释放SDA线 */
- iic_delay();
- }
- /**
- * @brief 不产生ACK应答
- * @param 无
- * @retval 无
- */
- void iic_nack(void)
- {
- IIC_SDA(1); /* SCL 0 -> 1 时 SDA = 1,表示不应答 */
- iic_delay();
- IIC_SCL(1); /* 产生一个时钟 */
- iic_delay();
- IIC_SCL(0);
- iic_delay();
- }
- /**
- * @brief IIC发送一个字节
- * @param data: 要发送的数据
- * @retval 无
- */
- void iic_send_byte(uint8_t data)
- {
- uint8_t t;
-
- for (t = 0; t < 8; t++)
- {
- IIC_SDA((data & 0x80) >> 7); /* 高位先发送 */
- iic_delay();
- IIC_SCL(1);
- iic_delay();
- IIC_SCL(0);
- data <<= 1; /* 左移1位,用于下一次发送 */
- }
- IIC_SDA(1); /* 发送完成, 主机释放SDA线 */
- }
- /**
- * @brief IIC读取一个字节
- * @param ack: ack=1时,发送ack; ack=0时,发送nack
- * @retval 接收到的数据
- */
- uint8_t iic_read_byte(uint8_t ack)
- {
- uint8_t i, receive = 0;
- for (i = 0; i < 8; i++ ) /* 接收1个字节数据 */
- {
- receive <<= 1; /* 高位先输出,所以先收到的数据位要左移 */
- IIC_SCL(1);
- iic_delay();
- if (IIC_READ_SDA)
- {
- receive++;
- }
-
- IIC_SCL(0);
- iic_delay();
- }
- if (!ack)
- {
- iic_nack(); /* 发送nACK */
- }
- else
- {
- iic_ack(); /* 发送ACK */
- }
- return receive;
- }
EEPROM操作代码如下:
- /* 最大容量 1KB */
- #define AT24C08_MAX_CAPACITY ((uint32_t)0x400)
- /* 单页大小 */
- #define AT24C08_PAGE_SIZE ((uint8_t)16)
- /* 设备地址 */
- #define AT24C08_DEV_ADDR ((uint8_t)0xA0)
- /* 延时 */
- static void bsp_delay(void)
- {
- volatile uint32_t ms = 0x3FFF; /* 2.5ms */
- while (--ms);
- }
- /* 写数据 */
- uint16_t bsp_at24c08_simulate_write(uint16_t addr, uint8_t *buf, uint16_t size)
- {
- uint16_t write_bytes = 0;
- uint8_t dev_addr = AT24C08_DEV_ADDR; /* 设备地址 */
- uint8_t mem_addr = addr; /* 存储地址 */
- uint16_t write_index = 0;
- uint8_t current_page_write_size = 0; /* 当前页写大小 */
-
- /* 入参检查 */
- if ((addr >= AT24C08_MAX_CAPACITY) || (size == 0) || ((addr + size) > AT24C08_MAX_CAPACITY)) {
- return write_bytes;
- }
-
- do {
- /* 计算地址 */
- dev_addr = AT24C08_DEV_ADDR + (((addr / AT24C08_PAGE_SIZE) >> 4) << 1);
- mem_addr = (addr % AT24C08_PAGE_SIZE) + (((addr / AT24C08_PAGE_SIZE) & 0x0F) << 4);
- current_page_write_size = AT24C08_PAGE_SIZE - (addr % AT24C08_PAGE_SIZE);
- current_page_write_size = (current_page_write_size <= (size - write_bytes)) ? current_page_write_size : (size - write_bytes);
- write_index = 0;
-
- iic_start();
- iic_send_byte(dev_addr);
- iic_wait_ack();
- iic_send_byte(mem_addr);
- iic_wait_ack();
- do {
- iic_send_byte(buf[write_bytes++]);
- iic_wait_ack();
- } while (++write_index < current_page_write_size);
- iic_stop();
- addr += current_page_write_size;
- bsp_delay();
- } while (write_bytes < size);
-
- return write_bytes;
- }
- /* 读数据 */
- uint16_t bsp_at24c08_simulate_read(uint16_t addr, uint8_t *buf, uint16_t size)
- {
- uint16_t read_bytes = 0;
- uint8_t dev_addr = AT24C08_DEV_ADDR; /* 设备地址 */
- uint8_t mem_addr = addr; /* 存储地址 */
- uint16_t read_index = 0;
- uint16_t current_page_read_size = 0; /* 当前页写大小 */
-
- /* 入参检查 */
- if ((addr >= AT24C08_MAX_CAPACITY) || (size == 0) || ((addr + size) > AT24C08_MAX_CAPACITY)) {
- return read_bytes;
- }
-
- do {
- /* 计算地址 */
- dev_addr = AT24C08_DEV_ADDR + (((addr / AT24C08_PAGE_SIZE) >> 4) << 1);
- mem_addr = (addr % AT24C08_PAGE_SIZE) + (((addr / AT24C08_PAGE_SIZE) & 0x0F) << 4);
- // current_page_read_size = AT24C08_PAGE_SIZE - (addr % AT24C08_PAGE_SIZE);
- // current_page_read_size = (current_page_read_size <= (size - read_bytes)) ? current_page_read_size : (size - read_bytes);
- read_index = 0;
- current_page_read_size = size;
-
- iic_start();
- iic_send_byte(dev_addr);
- iic_wait_ack();
- iic_send_byte(mem_addr);
- iic_wait_ack();
- iic_stop();
- iic_start();
- iic_send_byte(dev_addr | 0x01);
- iic_wait_ack();
- do {
- if ((read_index + 1) < current_page_read_size) {
- buf[read_bytes++] = iic_read_byte(1);
- } else {
- buf[read_bytes++] = iic_read_byte(0);
- }
- } while (++read_index < current_page_read_size);
- iic_stop();
- addr += current_page_read_size;
- } while (read_bytes < size);
-
- return read_bytes;
- }
测试代码如下:
- uint8_t w_buf[1024];
- uint8_t r_buf[1024];
- int8_t result = -1;
- // 应用初始化
- void app_init(void)
- {
- /* 模拟IIC */
- iic_init();
- for (uint16_t i = 0; i < sizeof(w_buf); i++) {
- w_buf[i] = 30 + i;
- }
- bsp_at24c08_simulate_write(0, w_buf, sizeof(w_buf));
- bsp_at24c08_simulate_read(0, r_buf, sizeof(r_buf));
-
- result = memcmp(w_buf, r_buf, sizeof(w_buf));
- }
- // 应用任务
- void app_task(void)
- {
- }
详细代码,请查看附件:
AT24C08_Simulate.zip
(1.99 MB, 下载次数: 3)
|