CH32V203C8T6部分模块简单实现。

文章详细介绍了嵌入式系统中几个关键通信模块的实现,包括TIM定时器的初始化和中断处理,UART/USART串口的配置和收发,CAN总线的初始化及数据传输,以及IIC硬件接口的读写操作。此外,还涉及了Flash存储器的擦写功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

TIM 定时器

UART/USART 串口收发

CAN 总线收发

IIC 硬件

IIC 软件

Flash擦写(字)


TIM 定时器

TIM.h

#define TIM3_ARR    48-1
#define TIM3_PSC    1000-1


#define TIM3_Priority           0
#define TIM3_SubPriority        1

TIM.c

//TIM3初始化
void DrvTimer3_Init(INT16U arr, INT16U psc) {

    TIM_TimeBaseInitTypeDef     TIM_TimeBaseStructure={0};
    NVIC_InitTypeDef            NVIC_InitStructure={0};

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能TIM3时钟
    TIM_TimeBaseStructure.TIM_Period = arr;   //指定下次更新事件时要加载到活动自动重新加载寄存器中的周期值。
    TIM_TimeBaseStructure.TIM_Prescaler = psc; //指定用于划分TIM时钟的预分频器值。
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频因子
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM计数模式,向上计数模式
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位

    //初始化TIM NVIC,设置中断优先级分组
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;           //TIM3中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //设置抢占优先级0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;        //设置响应优先级3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           //使能通道1中断
    NVIC_Init(&NVIC_InitStructure); //初始化NVIC
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //使能TIM3中断,允许更新中断
    TIM_Cmd(TIM3, ENABLE); //TIM3使能

}


//TIM3中断
void TIM3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void TIM3_IRQHandler(void) {
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) {
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

        /*
            实现你的功能
        */

    }
}

/******************************************************************/
//BSP实现
    DrvTimer3_Init(1000-1,48-1);//96M主频

UART/USART 串口收发

Usart.h

#ifndef __DRVUSART_H
#define __DRVUSART_H

#include "stdio.h"
#include "ch32v20x.h"


/* UART Printf Definition */
#define UartPort1    1
#define UartPort2    2
#define UartPort3    3

#define DEBUG_TRUE UartPort2

void DrvUsart_Init(uint8_t DEBUG, uint32_t baudrate);

void DrvUart_SendString(uint8_t Port, INT8U *str, INT8U len);


#if(DEBUG_TRUE)
  #define PRINT(format, ...)    printf(format, ##__VA_ARGS__)
#else
  #define PRINT(X...)
#endif



#endif //__DRVUSART_H

Usart.c

#include "usart.h"

void USART1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void USART2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void USART3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

//串口初始化(串口1、2、3)
void DrvUsart_Init(uint8_t DEBUG, uint32_t baudrate) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    if (DEBUG == UartPort1) {
        RCC_APB1PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        //PA9-rx PA10-tx
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
    } else if (DEBUG == UartPort2) {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
        //PA2-tx PA3-rx
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
    } else if (DEBUG == UartPort3) {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        //PB10-tx
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
    }

    USART_InitStructure.USART_BaudRate = baudrate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    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_Tx | USART_Mode_Rx;

    if (DEBUG == UartPort1) {
        USART_Init(USART1, &USART_InitStructure);
        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
        USART_Cmd(USART1, ENABLE);
    } else if (DEBUG == UartPort2) {
        USART_Init(USART2, &USART_InitStructure);
        USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
        NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
        USART_Cmd(USART2, ENABLE);
    } else if (DEBUG == UartPort3) {
        USART_Init(USART3, &USART_InitStructure);
        USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
        NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
        USART_Cmd(USART3, ENABLE);
    }
}

//重定义Print
__attribute__((used))
int _write(int fd, char *buf, int size) {
    int i;

    for (i = 0; i < size; i++) {
#if(DEBUG_TRUE == UartPort1)
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
        USART_SendData(USART1, *buf++);
#elif(DEBUG_TRUE == UartPort2)
        while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
        USART_SendData(USART2, *buf++);
#elif(DEBUG_TRUE == UartPort3)
        while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
        USART_SendData(USART3, *buf++);
#endif
    }

    return size;
}


void *_sbrk(ptrdiff_t incr) {
    extern char _end[];
    extern char _heap_end[];
    static char *curbrk = _end;

    if ((curbrk + incr < _end) || (curbrk + incr > _heap_end))
        return NULL - 1;

    curbrk += incr;
    return curbrk - incr;
}


//串口发送Byte
void DrvUart_SendByte(uint8_t Port, uint8_t byte) {
    switch (Port) {
    case 1: {
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
        USART_SendData(USART1, byte);
    }
        break;

    case 2: {
        while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
        USART_SendData(USART2, byte);
    }
        break;

    case 3: {
        while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
        USART_SendData(USART3, byte);
    }
        break;

    default:
        break;
    }
}

//串口发送String
void DrvUart_SendString(uint8_t Port, INT8U *str, INT8U len) {
    INT8U i = 0;
    for (i = 0; i < len; i++) {
        if (*str == '\r')
            DrvUart_SendByte(Port, 0x0d);
        else if (*str == '\n')
            DrvUart_SendByte(Port, 0x0a);
        else
            DrvUart_SendByte(Port, *str);
        str++;
    }
}

//串口1中断 DevProtocol_SetArray为处理接收数据的函数
void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        DevProtocol_SetArray(USART_ReceiveData(USART1));
    }
}

//串口2中断
void USART2_IRQHandler(void) {
    if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) {
        DevProtocol_SetArray(USART_ReceiveData(USART2));
    }
}


//串口3中断
void USART3_IRQHandler(void) {
    if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) {
        DevProtocol_SetArray(USART_ReceiveData(USART3));
    }
}

/***************************************************************/
//BSP实现
DrvUsart_Init(UartPort1,115200);
DrvUsart_Init(UartPort2,115200);
DrvUsart_Init(UartPort3,115200);

CAN 总线收发

CAN.h

#ifndef __DRVCAN_H
#define __DRVCAN_H

#include "stdio.h"
#include "ch32v20x.h"




/************************struct******************************/
typedef enum
{
    can_bps_125k,
    can_bps_250k,
    can_bps_500k,
    can_bps_1000k,
}CanBps;

/************************function******************************/
void DrvCan_Init(CanBps bps);
void DrvCan_SendMsg(INT8U slaver,INT8U cmd,INT8U motor_num,INT8U* msg,INT8U len);
u8 CAN_Receive_Msg(u8 *buf) ;

#endif //__DRVCAN_H

CAN.c

#include "CAN.h"


void USB_LP_CAN1_RX0_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
/*
*********************************************************************************************************
*   函  数  名 : DrvCan_Init
*   功能说明: CAN1初始化
*   形       参   : 无
*   返  回  值 : 无
*   创  建  人 : MXG
*   创建时间: 20230419
*********************************************************************************************************
*/
void DrvCan_Init(CanBps bps) {
    GPIO_InitTypeDef GPIO_InitSturcture;
    CAN_InitTypeDef CAN_InitSturcture;
    CAN_FilterInitTypeDef CAN_FilterInitSturcture;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

    GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
    //CAN1-tx
    GPIO_InitSturcture.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitSturcture.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitSturcture);
    //CAN1-rx
    GPIO_InitSturcture.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOB, &GPIO_InitSturcture);

    CAN_InitSturcture.CAN_TTCM = DISABLE;
    CAN_InitSturcture.CAN_ABOM = DISABLE;
    CAN_InitSturcture.CAN_AWUM = DISABLE;
    CAN_InitSturcture.CAN_NART = ENABLE;
    CAN_InitSturcture.CAN_RFLM = DISABLE;
    CAN_InitSturcture.CAN_TXFP = DISABLE;
    CAN_InitSturcture.CAN_Mode = CAN_Mode_Normal;

    switch (bps) {
    case can_bps_125k:
        CAN_InitSturcture.CAN_SJW = CAN_SJW_1tq;
        CAN_InitSturcture.CAN_BS1 = CAN_BS1_3tq;
        CAN_InitSturcture.CAN_BS2 = CAN_BS2_4tq;
        CAN_InitSturcture.CAN_Prescaler = 48;
        break;
    case can_bps_250k:
        CAN_InitSturcture.CAN_SJW = CAN_SJW_1tq;
        CAN_InitSturcture.CAN_BS1 = CAN_BS1_3tq;
        CAN_InitSturcture.CAN_BS2 = CAN_BS2_4tq;
        CAN_InitSturcture.CAN_Prescaler = 24;
        break;
    case can_bps_500k:
        CAN_InitSturcture.CAN_SJW = CAN_SJW_1tq;
        CAN_InitSturcture.CAN_BS1 = CAN_BS1_3tq;
        CAN_InitSturcture.CAN_BS2 = CAN_BS2_4tq;
        CAN_InitSturcture.CAN_Prescaler = 12;
        break;
    case can_bps_1000k:
        CAN_InitSturcture.CAN_SJW = CAN_SJW_1tq;
        CAN_InitSturcture.CAN_BS1 = CAN_BS1_3tq;
        CAN_InitSturcture.CAN_BS2 = CAN_BS2_4tq;
        CAN_InitSturcture.CAN_Prescaler = 6;
        break;
    default:
        break;
    }
    CAN_Init(CAN1, &CAN_InitSturcture);

    CAN_FilterInitSturcture.CAN_FilterNumber = 0;

    CAN_FilterInitSturcture.CAN_FilterMode = CAN_FilterMode_IdMask;
    CAN_FilterInitSturcture.CAN_FilterScale = CAN_FilterScale_32bit;
    CAN_FilterInitSturcture.CAN_FilterIdHigh = 0;
    CAN_FilterInitSturcture.CAN_FilterIdLow = 0;
    CAN_FilterInitSturcture.CAN_FilterMaskIdHigh = 0;
    CAN_FilterInitSturcture.CAN_FilterMaskIdLow = 0;
    CAN_FilterInitSturcture.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
    CAN_FilterInitSturcture.CAN_FilterActivation = ENABLE;
    CAN_FilterInit(&CAN_FilterInitSturcture);

    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

}

/*
*********************************************************************************************************
*   函 数 名: DrvCan_SendMsg
*   功能说明: Can发送数据
*   形    参: slaver 从设备ID,cmd 命令码,motor_num 电机号,msg数据,len长度
*   返 回 值: 无
*   创 建 人: MXG
*   创建时间: 20220219
*********************************************************************************************************
*/
void DrvCan_SendMsg(INT8U slaver,INT8U cmd,INT8U motor_num,INT8U* msg,INT8U len)
{
    u8 TransmitMailbox = 0;
    INT16U i = 0;
    INT16U Time_out        = 0xFFFF;
    CanTxMsg CAN_TxMessage;

    CAN_TxMessage.ExtId   = (motor_num <<16)+(cmd <<8) + slaver;     // 设置扩展标示符(29位)
    CAN_TxMessage.IDE     = CAN_ID_EXT;
    CAN_TxMessage.RTR     = CAN_RTR_Data;
    CAN_TxMessage.DLC     = len;
    for(i=0;i<len;i++)
    {
       CAN_TxMessage.Data[i] = msg[i];   //数据帧
    }
    TransmitMailbox = CAN_Transmit(CAN1, &CAN_TxMessage);
    while ((CAN_TransmitStatus(CAN1, TransmitMailbox) != CAN_TxStatus_Ok) && (Time_out != 0)) //等待发送结束
        Time_out--;
    Time_out = 0xFFFF;

}

/*
*********************************************************************************************************
*   函 数 名: USB_LP_CAN1_RX0_IRQHandler
*   功能说明: Can中断接收
*   形    参: 无
*   返 回 值: 无
*   创 建 人: MXG
*   创建时间: 20220219
*********************************************************************************************************
*/

void USB_LP_CAN1_RX0_IRQHandler(void)
{
    CanRxMsg CanRxStructure;

    if(CAN_GetITStatus(CAN1, CAN_IT_FMP0) != RESET)
    {
        CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0);

        CAN_Receive(CAN1, CAN_FIFO1, &CanRxStructure);

        DevProtocol_CanProcess(CanRxStructure);
    }
}


/***************************************************************/
//BSP实现
    DrvCan_Init(can_bps_1000k);

IIC 硬件

IIC.h

#if USE_HARDWARE_IIC //硬件IIC
#define MASTER_MODE    0  //主机
#define SLAVE_MODE   1  //从机
#define I2C_MODE    MASTER_MODE

#define SlaveAddress    0X0C        //MT6701 地址
#define ReadAddress1    0X03        //数据高位寄存器地址
#define ReadAddress2    0X04        //数据低位寄存器地址


void IIC_Init(u32 bound, u16 address);
void IIC2_Read(u16 ReadAddr, u8 *pBuffer, u16 NumToRead);

IIC.c

/*
*********************************************************************************************************
*   函  数  名 : IIC_Init
*   功能说明: IIC初始化
*   形       参   : 无
*   返  回  值 : 无
*   创  建  人 : MXG
*   创建时间: 20230419
*********************************************************************************************************
*/
void IIC_Init(u32 bound, u16 address) {
    GPIO_InitTypeDef GPIO_InitStructure = { 0 };
    I2C_InitTypeDef I2C_InitTSturcture = { 0 };

    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd( RCC_APB1Periph_I2C2, ENABLE);

    //SCL
    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);
    //SDA
    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_InitTSturcture.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitTSturcture.I2C_OwnAddress1 = address;
    I2C_InitTSturcture.I2C_Ack = I2C_Ack_Enable;
    I2C_InitTSturcture.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_Init( I2C2, &I2C_InitTSturcture);

    I2C_Cmd( I2C2, ENABLE);

    I2C_AcknowledgeConfig( I2C2, ENABLE);
}


/*
*********************************************************************************************************
*   函  数  名 : IIC2_ReadOneByte
*   功能说明: 读1byte
*   形       参   : ReadAddr-读写地址
*   返  回  值 : 无
*   创  建  人 : MXG
*   创建时间: 20230419
*********************************************************************************************************
*/
u8 IIC2_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 ) );
    I2C_Send7bitAddress( I2C2, 0XC, I2C_Direction_Transmitter);

    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) );

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

#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, 0X0C, I2C_Direction_Receiver);

    while( !I2C_CheckEvent( I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) );
    while( I2C_GetFlagStatus( I2C2, I2C_FLAG_RXNE ) == RESET )
    I2C_AcknowledgeConfig( I2C2, DISABLE );

    temp = I2C_ReceiveData( I2C2);
    I2C_GenerateSTOP( I2C2, ENABLE);

    return temp;
}

/*
*********************************************************************************************************
*   函  数  名 : IIC2_WriteOneByte
*   功能说明: WriteAddr-写地址 DataToWrite-写数据
*   形       参   : 无
*   返  回  值 : 无
*   创  建  人 : MXG
*   创建时间: 20230419
*********************************************************************************************************
*/
void IIC2_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, 0X0C, 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);
}

/*
*********************************************************************************************************
*   函  数  名 : IIC2_Read
*   功能说明: 连续读
*   形       参   : ReadAddr-读地址 pBuffer-存放数组 NumToRead-长度
*   返  回  值 : 无
*   创  建  人 : MXG
*   创建时间: 20230419
*********************************************************************************************************
*/
void IIC2_Read(u16 ReadAddr, u8 *pBuffer, u16 NumToRead) {
    while(NumToRead)
    {
        *pBuffer++=IIC2_ReadOneByte(ReadAddr++);
        NumToRead--;
    }
}

/*
*********************************************************************************************************
*   函  数  名 : IIC2_Write
*   功能说明: 连续写
*   形       参   : WriteAddr-写地址 pBuffer-写数据 NumToWrite-长度
*   返  回  值 : 无
*   创  建  人 : MXG
*   创建时间: 20230419
*********************************************************************************************************
*/
void IIC2_Write(u16 WriteAddr, u8 *pBuffer, u16 NumToWrite) {
    while(NumToWrite--)
    {
        IIC2_WriteOneByte(WriteAddr,*pBuffer);
        WriteAddr++;
        pBuffer++;
        Delay_Ms(2);
    }
}

IIC 软件

IIC.h

#define I2C_ADDRESS         0X0C

#define I2C_SCL_PORT        GPIOB
#define I2C_SCL_PIN         GPIO_Pin_10

#define I2C_SDA_PORT        GPIOB
#define I2C_SDA_PIN         GPIO_Pin_11

#define I2C_SDA_H           GPIO_SetBits(I2C_SDA_PORT, I2C_SDA_PIN)
#define I2C_SDA_L           GPIO_ResetBits(I2C_SDA_PORT, I2C_SDA_PIN)
#define I2C_SDA_R           GPIO_ReadInputDataBit(I2C_SDA_PORT, I2C_SDA_PIN)

#define I2C_SCL_H           GPIO_SetBits(I2C_SCL_PORT, I2C_SCL_PIN)
#define I2C_SCL_L           GPIO_ResetBits(I2C_SCL_PORT, I2C_SCL_PIN)

#define IIC_OK      1
#define IIC_Err     0

#define ACK_TIME            (200U)


/*********** Struct **********/
typedef struct
{
    INT16U speed;

} IIC_INFO;

typedef enum
{
    err_none =1,
    err_timout_t,
    err_timout_r,
    err_max_addr,
}err_I2C_code;

IIC.C

/*
*********************************************************************************************************
*   函 数 名: DrvI2C_Init
*   功能说明: i2c初始化
*   形    参: 无
*   返 回 值: 无
*   创 建 人: MXG
*   创建时间: 20201109
*********************************************************************************************************
*/
void DrvI2C_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    //PB10-SCL
    GPIO_InitStructure.GPIO_Pin     = I2C_SCL_PIN;
    GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_Out_OD;   //开漏输出,不用切换输入和输出
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
    GPIO_Init(I2C_SCL_PORT, &GPIO_InitStructure);
    //PB11-SDA
    GPIO_InitStructure.GPIO_Pin     = I2C_SDA_PIN;
    GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_Out_OD;   //开漏输出,不用切换输入和输出
    GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;
    GPIO_Init(I2C_SDA_PORT, &GPIO_InitStructure);

    I2C_SDA_H;
    I2C_SCL_H;
}

//IIC空闲状态

//当IIC总线的SDA和SCL两条信号线同时处于高电平时,规定为IIC总线的空闲状态

void I2C_Idle_State()
{
    I2C_SDA_H;
    I2C_SCL_H;

    Delay_Us(4);
}
/*
*********************************************************************************************************
*   函 数 名: DrvI2C_Start
*   功能说明: 软件IIC开始信号
*   形    参: 无
*   返 回 值: 无
*   创 建 人: MXG
*   创建时间: 20201109
*********************************************************************************************************
*/
void DrvI2C_Start(void)
{
    I2C_SDA_H;
    I2C_SCL_H;
    Delay_Us(4);

    I2C_SDA_L;
    Delay_Us(4);
    I2C_SCL_L;
    Delay_Us(4);
}
/*
*********************************************************************************************************
*   函 数 名: DrvI2C_Stop
*   功能说明: 软件IIC停止信号
*   形    参: 无
*   返 回 值: 无
*   创 建 人: MXG
*   创建时间: 20201109
*********************************************************************************************************
*/
void DrvI2C_Stop(void)
{
    I2C_SDA_L;                      //拉低SDA线
    I2C_SCL_L;                      //拉低SCL先
    Delay_Us(4);

    I2C_SCL_H;                      //拉高SCL线
    I2C_SDA_H;                      //拉高SDA线,当SCL线为高时,SDA线一个上升沿代表停止信号
    Delay_Us(4);
}
/*
*********************************************************************************************************
*   函 数 名: DrvI2C_WaitAck
*   功能说明: 软件IIC等待ACK应答
*   形    参: 超时时间
*   返 回 值: 无
*   创 建 人: MXG
*   创建时间: 20201109
*********************************************************************************************************
*/
u8 DrvI2C_WaitAck(INT32U timeOut)
{
    I2C_SDA_H;      //拉高SDA线
    Delay_Us(4);
    I2C_SCL_H;      //拉高SCL线
    Delay_Us(4);

    while(I2C_SDA_R)                        //如果读到SDA线为1,则等待。应答信号应是0
    {
        if(--timeOut == 0)
        {
            DrvI2C_Stop();                  //超时未收到应答,则停止总线

            return IIC_Err;                 //返回失败
        }

        Delay_Us(4);
    }

    I2C_SCL_L;                              //拉低SCL线,以便继续收发数据

    return IIC_OK;                          //返回成功
}
/*
*********************************************************************************************************
*   函 数 名: DrvI2C_Ack
*   功能说明: 软件IIC产生一个应答
*   形    参: 无
*   返 回 值: 无
*   创 建 人: MXG
*   创建时间: 20201109
*********************************************************************************************************
*/
void DrvI2C_Ack(void)
{
    I2C_SCL_L;                      //拉低SCL线
    I2C_SDA_L;                      //拉低SDA线
    Delay_Us(4);
    I2C_SCL_H;                      //拉高SCL线
    Delay_Us(4);
    I2C_SCL_L;                      //拉低SCL线
}
/*
*********************************************************************************************************
*   函 数 名: DrvI2C_Ack
*   功能说明: 软件IIC产生一个非应答
*   形    参: 无
*   返 回 值: 无
*   创 建 人: MXG
*   创建时间: 20201109
*********************************************************************************************************
*/
void DrvI2C_NAck(void)
{
    I2C_SCL_L;                      //拉低SCL线
    I2C_SDA_H;                      //拉高SDA线
    Delay_Us(4);
    I2C_SCL_H;                      //拉高SCL线
    Delay_Us(4);
    I2C_SCL_L;                      //拉低SCL线
}
/*
*********************************************************************************************************
*   函 数 名: DrvI2C_SendByte
*   功能说明: 软件IIC发送一个字节
*   形    参: 需要发送的字节
*   返 回 值: 无
*   创 建 人: MXG
*   创建时间: 20201109
*********************************************************************************************************
*/
void DrvI2C_SendByte(INT8U byte)
{

    INT8U count = 0;

    I2C_SCL_L;                          //拉低时钟开始数据传输

    for(; count < 8; count++)       //循环8次,每次发送一个bit
    {
        if(byte & 0x80)             //发送最高位
            I2C_SDA_H;
        else
            I2C_SDA_L;

        byte <<= 1;                 //byte左移1位

        Delay_Us(4);
        I2C_SCL_H;
        Delay_Us(4);
        I2C_SCL_L;
    }

}
/*
*********************************************************************************************************
*   函 数 名: DrvI2C_RecvByte
*   功能说明: 软件IIC接收一个字节
*   形    参: 无
*   返 回 值: 接收到的字节
*   创 建 人: MXG
*   创建时间: 20201109
*********************************************************************************************************
*/
INT8U DrvI2C_RecvByte(void)
{
    INT8U count = 0, receive = 0;

    I2C_SDA_H;                      //拉高SDA线,开漏状态下,需线拉高以便读取数据

    for(; count < 8; count++ )      //循环8次,每次发送一个bit
    {
        I2C_SCL_L;
        Delay_Us(4);
        I2C_SCL_H;

        receive <<= 1;              //左移一位

        if(I2C_SDA_R)               //如果SDA线为1,则receive变量自增,每次自增都是对bit0的+1,然后下一次循环会先左移一次
            receive++;

        Delay_Us(4);
    }

    return receive;

}
/*
*********************************************************************************************************
*   函 数 名: DrvI2C_ReadByte
*   功能说明: 读数据
*   形    参: 起始地址
*   返 回 值: 成功/失败
*   创 建 人: MXG
*   创建时间: 20210125
*********************************************************************************************************
*/
INT8U DrvI2C_ReadByte(INT8U ReadAddr,INT8U *data)
{
    DrvI2C_Start();

    DrvI2C_SendByte(I2C_ADDRESS);      //发送写命令

    *data = 0;

    if( !DrvI2C_WaitAck(ACK_TIME))
        return err_timout_t;

    DrvI2C_SendByte(ReadAddr&0xff);   //发送地址

    if( !DrvI2C_WaitAck(ACK_TIME))
        return err_timout_t;

    DrvI2C_Start();
    DrvI2C_SendByte(I2C_ADDRESS+1);    //发送读命令
    if( !DrvI2C_WaitAck(ACK_TIME))
        return err_timout_t;

    *data=DrvI2C_RecvByte();
    DrvI2C_NAck();      //不带ACK的


    DrvI2C_Stop();//产生一个停止条件
    return 1; //status == 0;
}
/*
*********************************************************************************************************
*   函 数 名: DrvI2C_ReadBytes
*   功能说明: 读多个数据
*   形    参: 起始地址
*   返 回 值: 成功/失败
*   创 建 人: MXG
*   创建时间: 20210125
*********************************************************************************************************
*/
INT8U DrvI2C_ReadBytes(INT8U ReadAddr,INT16U length,INT8U *data)
{
    INT16U count = 0;
    for( count = 0; count < length; count ++)
    {
        DrvI2C_ReadByte(ReadAddr +count,&data[count]);
    }
    return 0;
}
#endif

Flash擦写(字)

.h

/* Global define */
typedef enum {
    FAILED = 0, PASSED = !FAILED
} TestStatus;
#define PAGE_WRITE_START_ADDR  ((uint32_t)0x0800F000) /* Start from 60K */
#define PAGE_WRITE_END_ADDR    ((uint32_t)0x08010000) /* End at 64K */
#define FLASH_PAGE_SIZE                   4096
#define FLASH_PAGES_TO_BE_PROTECTED FLASH_WRProt_Pages60to63

/* Fast Mode define */
#define FAST_FLASH_PROGRAM_START_ADDR  ((uint32_t)0x08008000) //32K
#define FAST_FLASH_PROGRAM_END_ADDR  ((uint32_t)0x08010000)   //64k
#define FAST_FLASH_SIZE  (64*1024) //Flash总内存

.c

/************************************************************
 * File Name:        DrvFlash.c
 * File Instruction: 该文件为Flash驱动文件
 * File User:        Phyllis
 * File TIME:        2022-02-19
 * File Version:     V1.0
 ************************************************************/
#include "flash.h"


/* Global Variable */
uint32_t EraseCounter = 0x0, Address = 0x0;
uint16_t Data = 0xAAAA;
uint32_t WRPR_Value = 0xFFFFFFFF, ProtectedPages = 0x0;
uint32_t NbrOfPage;
volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;
volatile TestStatus MemoryProgramStatus = PASSED;
volatile TestStatus MemoryEraseStatus = PASSED;
u32 buf[64];

/*
 *********************************************************************************************************
 *   函 数 名: DrvFlash_WriteWords
 *   功能说明: Flash写一个word,32位
 *   形    参: 地址,数据,字长
 *   返 回 值: 错误码
 *   创 建 人: MXG
 *   创建时间: 20220219
 *********************************************************************************************************
 */
errcode DrvFlash_WriteWords(INT32U addr, INT32U *buff, INT32U len) {

    errcode err_code = flasherr_none;
    INT8U i = 0;
    //系统时钟超过100M时需要降频
    RCC->CFGR0 |= (uint32_t) RCC_HPRE_DIV2;
    __disable_irq();

    FLASH_Unlock();


    FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_WRPRTERR);

    //擦
        FLASHStatus = FLASH_ErasePage(addr); //Erase 4KB
        if (FLASHStatus != FLASH_COMPLETE) {
            err_code = flasherr_Erase;
            return err_code;
        }
        Address = addr;
    //写
        while((i < len) && (FLASHStatus == FLASH_COMPLETE))
        {
          FLASHStatus = FLASH_ProgramWord(Address, buff[i++]);
          Address = Address + 4;
        }


    FLASH_Lock();

    RCC->CFGR0 &= ~(uint32_t) RCC_HPRE_DIV2;
    __enable_irq();
    return err_code;
}

/*
 *********************************************************************************************************
 *   函 数 名: DrvFlash_ReadWord
 *   功能说明: Flash读一个word
 *   形    参: 地址
 *   返 回 值: 数据
 *   创 建 人: MXG
 *   创建时间: 20220219
 *********************************************************************************************************
 */
INT32U DrvFlash_ReadWord(INT32U addr) {
    return *(vu32*) addr;
}
/*
 *********************************************************************************************************
 *   函 数 名: DrvFlash_ReadWords
 *   功能说明: Flash读多个world
 *   形    参: 地址
 *   返 回 值: 数据
 *   创 建 人: MXG
 *   创建时间: 20220219
 *********************************************************************************************************
 */
errcode DrvFlash_ReadWords(INT32U addr, INT32U *buff, INT32U len) {
    INT8U i = 0;
    errcode err_code = flasherr_none;

    //对4k
//    for(i=0; i<1024; i++){
//            buff[i] = *(u32*)(PAGE_WRITE_START_ADDR+4*i);
//    }

    for(i=0; i<len; i++){
            buff[i] = *(u32*)(addr+4*i);
    }

    return err_code;
}

更新ing...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值