打印
[RISC-V MCU 应用开发]

【RISC-V MCU CH32V103测评】05:硬件IIC读写EEPROM测试

[复制链接]
644|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 天意无罪 于 2020-12-13 17:18 编辑

话说今天就是CH32V103开发板评测活动的最后一天了,之前想好的idea:PWM驱动RGB灯、和NOKIA5110 贪吃蛇游戏都还没来得及测试。哎,加班狗的日子太难了,趁着最后一天再写一个测试贴吧。

(一)  硬件熟悉
内部集成电路总线(I2C)广泛用在微控制器和传感器及其他片外模块的通讯上,它本身支持多主多从模式,仅仅使用两根线(SDA 和 SCL)就能以 100KHz(标准)和 400KHz(快速)两种速度通讯。I2C 总线还兼容 SMBus 协议,不仅支持 I2C 的时序,还支持仲裁、定时和 DMA,拥有 CRC 校验功能。

CH32V103 系列产品内部集成2路硬件IIC,IIC1和IIC2,引脚分布如下:
IIC1_SCL:PB6;
IIC1_SDA:PB7;
IIC2_SCL:PB10;
IIC2_SDA:PB11;


从开发板原理图可知,板上EEPROM器件的IIC引脚为悬空,需要使用杜邦线将其与MCU的IO相连。该试验使用IIC2,连线说明如下:
J5的SCL连接PB10;
J5的SDA连接PB11;



(二)  软件设计
实现功能:在EEPROM指定起始地址写入一串字符,并将其读出来然后通过串口打印。
1. 在BSP/src目录下新建一个at24c02.c文件,在BSP/inc目录下新建一个at24c02.h文件。
2.在at24c02.h文件里面定义相关宏定义、变量声明、以及函数声明等。
/*
* at24c02.h
*
*  Created on: Dec 13, 2020
*      Author: dengrb
*/

#ifndef BSP_INC_AT24C02_H_
#define BSP_INC_AT24C02_H_

#include "ch32v10x_conf.h"

/* EERPOM DATA ADDRESS Length Definition */
#define Address_8bit  0
#define Address_16bit  1

/* EERPOM DATA ADDRESS Length Selection */
#define Address_Lenth   Address_8bit
//#define Address_Lenth   Address_16bit

void IIC_Init( u32 bound, u16 address );
void AT24CXX_Init(void);
u8 AT24CXX_ReadOneByte(u16 ReadAddr);
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite);
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);

#endif /* BSP_INC_AT24C02_H_ */
3.  在at24c02.c文件里面实现IIC和at24c02的配置和初始化,以及读写函数等。
/*
* at24c02.c
*
*  Created on: Dec 13, 2020
*      Author: dengrb
*/
#include "at24c02.h"

/*******************************************************************************
* Function Name  : IIC_Init
* Description    : Initializes the IIC peripheral.
* Input          : None
* Return         : None
*******************************************************************************/
void IIC_Init( u32 bound, u16 address )
{
    GPIO_InitTypeDef GPIO_InitStructure;
    I2C_InitTypeDef I2C_InitTSturcture;

    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //使能GPIOB时钟
    RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C2, ENABLE );  //使能I2C2时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //开漏复用模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init( GPIOB, &GPIO_InitStructure );

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //开漏复用模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init( GPIOB, &GPIO_InitStructure );

    I2C_InitTSturcture.I2C_ClockSpeed = bound;          //设置时钟频率
    I2C_InitTSturcture.I2C_Mode = I2C_Mode_I2C;         //设置I2C模式
    I2C_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_2; //设置I2C快速模式占空比。
    I2C_InitTSturcture.I2C_OwnAddress1 = address;       //设置第一个设备自己的地址
    I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;        //使能应答
    I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //设置为7位应答
    I2C_Init( I2C2, &I2C_InitTSturcture );              //I2C初始化

    I2C_Cmd( I2C2, ENABLE );               //使能I2C2

    I2C_AcknowledgeConfig( I2C2, ENABLE ); //使能I2C2应答功能
}

/*******************************************************************************
* Function Name  : AT24CXX_Init
* Description    : Initializes AT24xx EEPROM.
* Input          : None
* Return         : None
********************************************************************************/
void AT24CXX_Init(void)
{
    IIC_Init( 100000, 0xA0);
}

/*******************************************************************************
* Function Name  : AT24CXX_ReadOneByte
* Description    : Read one data from EEPROM.
* Input          : ReadAddr: Read frist address.
* Return         : temp: Read data.
********************************************************************************/
u8 AT24CXX_ReadOneByte(u16 ReadAddr)
{
    u8 temp=0;

    while( I2C_GetFlagStatus( I2C2, I2C_FLAG_BUSY ) != RESET ); //等待总线空闲
    I2C_GenerateSTART( I2C2, ENABLE ); //开始信号

    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_MODE_SELECT ) ); //检测EV5事件并清除标志
    I2C_Send7bitAddress( I2C2, 0XA0, I2C_Direction_Transmitter );   //发送设备地址+写信号

    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) ); //检测EV6事件并清除标志

#if (Address_Lenth  == Address_8bit)
    I2C_SendData( I2C2, (u8)(ReadAddr&0x00FF) ); //发送数据地址
    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) ); //检测EV8事件并清除标志

#elif (Address_Lenth  == Address_16bit)
    I2C_SendData( I2C2, (u8)(ReadAddr>>8) );
    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );

    I2C_SendData( I2C2, (u8)(ReadAddr&0x00FF) );
    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );

#endif

    I2C_GenerateSTART( I2C2, ENABLE );

    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_MODE_SELECT ) );
    I2C_Send7bitAddress( I2C2, 0XA0, I2C_Direction_Receiver );

    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) ); //检测EV6事件并清除标志
    while( I2C_GetFlagStatus( I2C2, I2C_FLAG_RXNE ) ==  RESET )
    I2C_AcknowledgeConfig( I2C2, DISABLE ); //发送非应答信号

    temp = I2C_ReceiveData( I2C2 );   //接收数据
    I2C_GenerateSTOP( I2C2, ENABLE ); //停止信号

    return temp;
}

/*******************************************************************************
* Function Name  : AT24CXX_WriteOneByte
* Description    : Write one data to EEPROM.
* Input          : WriteAddr: Write frist address.
* Return         : DataToWrite: Write data.
********************************************************************************/
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{
    while( I2C_GetFlagStatus( I2C2, I2C_FLAG_BUSY ) != RESET );
    I2C_GenerateSTART( I2C2, ENABLE );

    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_MODE_SELECT ) );
    I2C_Send7bitAddress( I2C2, 0XA0, I2C_Direction_Transmitter );

    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) );

#if (Address_Lenth  == Address_8bit)
    I2C_SendData( I2C2, (u8)(WriteAddr&0x00FF) );
    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );

#elif (Address_Lenth  == Address_16bit)
    I2C_SendData( I2C2, (u8)(WriteAddr>>8) );
    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );

    I2C_SendData( I2C2, (u8)(WriteAddr&0x00FF) );
    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );

#endif

    if( I2C_GetFlagStatus( I2C2, I2C_FLAG_TXE ) !=  RESET )
    {
        I2C_SendData( I2C2, DataToWrite );
    }

    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED ) );
    I2C_GenerateSTOP( I2C2, ENABLE );
}

/*******************************************************************************
* Function Name  : AT24CXX_Read
* Description    : Read multiple data from EEPROM.
* Input          : ReadAddr: Read frist address. (AT24c02: 0~255)
*                  pBuffer: Read data.
*                  NumToRead: Data number.
* Return         : None
********************************************************************************/
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
{
    while(NumToRead)
    {
        *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
        NumToRead--;
    }
}

/*******************************************************************************
* Function Name  : AT24CXX_Write
* Description    : Write multiple data to EEPROM.
* Input          : WriteAddr: Write frist address. (AT24c02: 0~255)
*                  pBuffer: Write data.
*                  NumToWrite: Data number.
* Return         : None
********************************************************************************/
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
    while(NumToWrite--)
    {
        AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
        WriteAddr++;
        pBuffer++;
        Delay_Ms(2);
    }
}
4.  在main.c中添加测试代码。
#include <stdio.h>
#include <string.h>

#include "debug.h"
#include "led.h"
#include "usart.h"
#include "tkey.h"
#include "at24c02.h"
/* Global typedef */

/* Global define */

/* Global Variable */
u8 Write_Data[100]="Hello world!This is EEPROM Write and Read Test!";
u8 Read_Data[100];
/*******************************************************************************
* Function Name  : main
* Description    : Main program.
* Input          : None
* Return         : None
*******************************************************************************/
int main(void)
{
        Delay_Init();
        USART_Printf_Init(115200);
        AT24CXX_Init();
        LED_Init();

        printf("SystemClk:%d\r\n",SystemCoreClock);

        LED1_ON();
        printf("Start Write 24Cxx....\r\n");
        AT24CXX_Write(100,(u8*)Write_Data,47);      //写入数据
        printf("24Cxx Write Sucess!\r\n");
        LED1_OFF();
        Delay_Ms(1000);

        LED2_ON();
        printf("Start Read 24Cxx....\r\n");
        AT24CXX_Read(100,Read_Data,47);               //读取数据
        printf("The Data Readed Is: \r\n");
        printf("%s\r\n", Read_Data);                    //打印输出数据
        LED2_OFF();

        while(1)
        {
        }
}

(三) 效果演示








使用特权

评论回复

相关帖子

沙发
fuqinyyy| | 2020-12-13 17:23 | 只看该作者
这次活动没参加到,希望再来一次啊,话说楼主这个GIF图片是用什么制作的?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

61

主题

2993

帖子

12

粉丝