GD32F303CC定时器配置

以timer1为例,实现简单的定时频率为10KHZ和间隔100us触发中断。

从芯片规格书得知,timer1在APB1总线上,外设时钟为最大60MHZ限制,而芯片的系统时钟是120MHZ,说明这里AHB-->APB1使用了2分频,根据规格书描述,分频不为1,timer1的时钟频率为60MHZ*2=120MHZ.这里明确时钟源频率就好办了,按以下步骤配置即可:

1、使能timer1时钟

rcu_periph_clock_enable(RCU_TIMER1);

2、配置定时器参数,这里通过一个结构体来配置   

    timer_parameter_struct timer_initpara;

    timer_initpara.clockdivision = TIMER_CKDIV_DIV1;

    timer_initpara.prescaler = 119;//time1-APB1(60MHZ)--->time1clk(60MHZ*2) 1MHZ

    timer_initpara.period = 99;//99-10khz---100US,999-1KHZ---1MS

    timer_initpara.alignedmode = TIMER_COUNTER_EDGE;//向上/向下计数,通过counterdirection指定。

    timer_initpara.counterdirection = TIMER_COUNTER_UP;//当alignedmode = TIMER_COUNTER_EDGE时,才设置有效果。

    timer_initpara.repetitioncounter = 0;//表示在0+1周期更新计数寄存器的值。

    timer_init(TIMER1,&timer_initpara);

3、使能中断,这里分timer1 的全局中断和子中断

    nvic_irq_enable(TIMER1_IRQn,3,3);
    timer_interrupt_enable(TIMER1,TIMER_INT_UP);

4、使能定时器,这里其实就是开始计数的意思

    timer_enable(TIMER1);

5、编写中断函数逻辑

extern uint32_t tick_1msCnt;
void TIMER1_IRQHandler(void)
{
    timer_interrupt_flag_clear(TIMER1,TIMER_INT_FLAG_UP);
    tick_1msCnt++;

}

以下提供全部代码,并测试,验证30S的时间是否准确。


#include "gd32f30x.h"
#include "gd32f30x_eval.h"
#include "systick.h"


#define GD32F30X_CL
uint32_t tick_1msCnt;


/*
*设置timer1 100us中断一次
*/
void timer1_config()
{
    timer_parameter_struct timer_initpara;

    timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
    timer_initpara.prescaler = 119;//time1-APB1(60MHZ)--->time1clk(60MHZ*2) 1MHZ
    timer_initpara.period = 99;//99-10khz---100US,999-1KHZ---1MS
    timer_initpara.alignedmode = TIMER_COUNTER_EDGE;//向上/向下计数,通过counterdirection指定。
    timer_initpara.counterdirection = TIMER_COUNTER_UP;//当alignedmode = TIMER_COUNTER_EDGE时,才设置有效果。
    timer_initpara.repetitioncounter = 0;//表示在0+1周期更新计数寄存器的值。
    timer_init(TIMER1,&timer_initpara);

    nvic_irq_enable(TIMER1_IRQn,3,3);
    timer_interrupt_enable(TIMER1,TIMER_INT_UP);
    timer_enable(TIMER1);
}

void timer_config(void)
{



    rcu_periph_clock_enable(RCU_TIMER1);
    timer1_config();//100us一次中断

}
int main(void)
{
	systick_config();
    timer_config();
	while (1)
	{
		if(tick_1msCnt >=300000)
        {
            tick_1msCnt = 0;
        }
	}
	
}

<think>嗯,用户之前提到的是使用GD32F303CCT6的PA1、PA2、PA3引脚来模拟I2C,驱动某个设备,其中INT、SDA、SCL分别连接这三个引脚。现在需要优化驱动程序。首先,我需要回顾一下用户之前的问题,确保我理解正确。 首先,GD32F303是兆易创新的ARM Cortex-M4微控制器,和STM32F303类似,可能库函数也类似。用户用软件模拟IIC,可能是因为硬件I2C有问题或者需要更灵活的控制。PA1作为INT,应该是中断引脚,用于检测从设备的状态,比如数据准备好或者有事件发生。PA2是SDA,PA3是SCL,这两个是I2C的数据和时钟线。 优化驱动程序需要考虑几个方面:时序的精确性、代码的效率、错误处理、中断的使用,以及可能的电源管理。首先,软件I2C的关键在于时序的准确性,所以需要确保延时函数的精确性。GD32的主频是多少呢?用户没有提,可能需要根据系统时钟来调整延时。或者使用定时器来生成精确的延时,而不是简单的循环延时。 其次,代码结构方面,可能需要将GPIO的操作封装成函数,比如SDA和SCL的置高置低,以及读取SDA的状态。这样代码更模块化,便于维护和调试。另外,I2C的起始条件、停止条件、发送数据、接收数据、ACK/NACK的处理都需要函数化。 然后,错误处理方面,软件I2C容易受到干扰,导致通信失败,所以需要加入超时机制,避免程序卡死。比如在等待ACK的时候,设置一个超时计数器,超过一定时间就返回错误,并进行重试。 中断方面,PA1作为INT引脚,应该配置为外部中断输入,当从设备有数据时触发中断,主控制器可以及时响应。这样能提高系统的实时性,而不是轮询方式。需要配置GPIO的中断,并编写相应的中断服务函数,处理从设备的中断信号。 另外,可能要考虑上拉电阻的问题,软件I2C需要外部上拉电阻,确保SDA和SCL线在空闲时为高电平。用户是否已经添加了这些电阻?如果没有,可能需要在代码中配置GPIO为开漏模式,并启用内部上拉(如果芯片支持的话),不过GD32的GPIO模式设置可能需要检查。 还有,时钟速度的问题,软件模拟的I2C速度不能太高,一般可能在100kHz左右,需要根据实际需求调整延时时间。如果用户需要更高的速度,可能需要优化延时函数,或者使用硬件I2C。 代码优化方面,可以内联一些函数,或者使用宏定义来减少函数调用的开销,提高速度。另外,避免在关键时序部分被中断打断,可能需要暂时关闭中断,保证时序的准确性。 测试和调试方面,可能需要用逻辑分析仪或者示波器检查SDA和SCL的波形,确保时序符合I2C标准。同时,通过打印调试信息或者LED指示,帮助排查通信故障。 最后,驱动程序的结构,可能需要将I2C的模拟部分独立成模块,方便其他部分的调用,提高代码的复用性。比如,i2c_sw.h和i2c_sw.c,包含初始化、读写函数等。 总结下来,优化的方向可能包括: 1. 精确的延时函数,使用系统时钟或定时器。 2. 模块化GPIO操作,封装成函数或宏。 3. 加入超时和重试机制,提高鲁棒性。 4. 配置INT引脚的中断处理,提高响应速度。 5. 检查GPIO模式是否正确(开漏加上拉)。 6. 优化代码结构,减少函数调用开销。 7. 错误处理和状态反馈。 8. 测试和调试手段的加入。 可能需要询问用户是否有具体的代码示例,或者现有的驱动存在什么问题,以便更有针对性地优化。比如,是否有通信不稳定的情况,或者是速度不够的问题。但根据现有信息,先按照常规优化方法进行建议。</think>根据您的硬件连接和驱动需求,我将从以下几个方面为您优化GD32F303CCT6的软件模拟I2C驱动程序: --- ### **一、硬件连接确认** - **PA1**:INT(中断输入,需配置为上拉输入模式) - **PA2**:SDA(双向数据线,需配置为开漏输出模式) - **PA3**:SCL(时钟线,需配置为开漏输出模式) --- ### **二、关键优化策略** #### **1. 时序精准度优化** ```c #define I2C_DELAY_US 5 // 根据实际时钟调整 static void i2c_delay(void) { uint32_t tick = SysTick->VAL; while ((tick - SysTick->VAL) < (SystemCoreClock / 1000000 * I2C_DELAY_US)); } ``` #### **2. GPIO操作封装(宏定义加速)** ```c // SDA操作 #define SDA_HIGH() GPIO_BOP(GPIOA) = GPIO_PIN_2 // 释放SDA #define SDA_LOW() GPIO_BC(GPIOA) = GPIO_PIN_2 // 拉低SDA #define READ_SDA() (gpio_input_bit_get(GPIOA, GPIO_PIN_2)) // 读取SDA // SCL操作 #define SCL_HIGH() GPIO_BOP(GPIOA) = GPIO_PIN_3 #define SCL_LOW() GPIO_BC(GPIOA) = GPIO_PIN_3 ``` --- ### **三、中断处理优化** ```c // 配置PA1为中断输入 void INT_Config(void) { rcu_periph_clock_enable(RCU_GPIOA); gpio_init(GPIOA, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_1); nvic_irq_enable(EXTI1_IRQn, 2, 0); // 配置中断优先级 syscfg_exti_line_config(EXTI_SOURCE_GPIOA, EXTI_SOURCE_PIN1); exti_init(EXTI_1, EXTI_INTERRUPT, EXTI_TRIG_FALLING); // 下降沿触发 } // 中断服务函数 void EXTI1_IRQHandler(void) { if (exti_interrupt_flag_get(EXTI_1) != RESET) { exti_interrupt_flag_clear(EXTI_1); // 处理从设备中断请求 i2c_read_data(); // 触发I2C数据读取 } } ``` --- ### **四、I2C协议改进** #### **1. 增加超时重试机制** ```c #define I2C_TIMEOUT 1000 // 超时计数器阈值 uint8_t i2c_wait_ack(void) { uint32_t timeout = 0; SDA_HIGH(); i2c_delay(); SCL_HIGH(); while (READ_SDA()) { if (++timeout > I2C_TIMEOUT) { i2c_stop(); // 强制终止通信 return 1; // 返回错误 } } SCL_LOW(); return 0; } ``` #### **2. 改进数据读写函数** ```c // 带CRC校验的写入函数 uint8_t i2c_write_byte(uint8_t dev_addr, uint8_t reg, uint8_t *data, uint8_t len) { i2c_start(); if (i2c_send_byte(dev_addr << 1)) return 1; if (i2c_send_byte(reg)) return 1; for (uint8_t i=0; i<len; i++) { if (i2c_send_byte(data[i])) return 1; } // 添加CRC校验字节 uint8_t crc = calculate_crc(data, len); if (i2c_send_byte(crc)) return 1; i2c_stop(); return 0; } ``` --- ### **五、调试辅助** ```c // 通过串口打印I2C状态 void i2c_debug_log(uint8_t status) { if (status) { printf("[I2C Error] Code: 0x%02X\n", status); } else { printf("[I2C] Operation Success\n"); } } ``` --- ### **六、完整驱动架构** ```c /* i2c_sw.h */ typedef enum { I2C_OK = 0, I2C_ERR_START, I2C_ERR_ADDR, I2C_ERR_TX, I2C_ERR_RX, I2C_ERR_TIMEOUT } I2C_Status; void I2C_Init(void); I2C_Status I2C_Write(uint8_t dev_addr, uint8_t reg, uint8_t *data, uint16_t len); I2C_Status I2C_Read(uint8_t dev_addr, uint8_t reg, uint8_t *buf, uint16_t len); ``` --- ### **优化总结** 1. **时序可靠性**:通过SysTick实现微秒级精准延时 2. **故障恢复**:超时机制+自动重试(建议最多3次重试) 3. **代码效率**:宏定义替代函数调用,减少堆栈开销 4. **可维护性**:模块化设计,状态机清晰 5. **EMI防护**:在SCL/SDA线上增加软件滤波(连续3次采样一致才确认电平) 建议在实际使用时配合示波器或逻辑分析仪验证时序波形,特别注意SCL高电平期间SDA变化的建立/保持时间是否符合从器件要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值