MCU驱动使用(二)

浏览: 作者:Rocky 来源:AGM 时间:2025-04-30 分类:FPGA应用

五、Base Timer的使用:

六、gpTimer的使用:

    1、用于简单定时

    2、用于pwm输出

    3、输出反向PWM(带死区)

    4、输出任意波形

    5、用于输入捕获

七、Uart的使用

八、IIC的使用

九、CAN的使用


五、Base Timer的使用:

AG32中包含2个Base Timer:分别对应TIMER0和TIMER1。

这两个timer中,每个又有两组寄存器,每组寄存器可以单独产生定时。

所以,真正可用的普通定时器有4个:TIMER0-0、TIMER0-1、TIMER1-0、TIMER1-1。

4个定时器均可独立设置。

普通定时器特点:


定时器支持16位和32位的设置,

支持3种类型分频(1分频,16分频,256分频),

支持单次定时和循环定时。


驱动API函数命名中的1和2,分别对应第一组和第二组寄存器。也就是说,一个Timer可以用于2个独立计时器。

如,TIM_Init1设置的是第一组寄存器,TIM_Init2设置的是第二组寄存器。


举例:

用Timer1的group2产生1s的循环定时:


1


中断函数TIMER1_isr在SDK中已经默认指定。

说明:

设置函数:TIM_Init1 <-> TIM_SetLoad1/TIM_SetSize1/TIM_SetMode1/...

中断函数:TIMER0_isr/TIMER1_isr

函数说明:

void TIM_Init1(TIMER_TypeDef *tim, uint32_t timeInUs, TIMER_ModeTypeDef mode)

作用:启动Timer0或Timer1的第一个定时器(TIM_Init2则启动第二个定时器)。

参数:tim:TIMER0 or TIMER1

  timeInUs:多少us触发定时

  mode:TIMER_MODE_PERIODIC:循环触发  TIMER_CTRL_ONESHOT:只触发一次

举例:

  TIM_Init1(TIMER0, 500000, TIMER_MODE_PERIODIC);  

表示启动TIMER0的第一个定时器,500ms触发一次定时中断,循环触发。

除了直接调用 TIM_Init1来启动一个定时外,也可以调用各个子函数来启动。

如,

  TIM_Init2(TIMER0, 500000, TIMER_MODE_PERIODIC)

功能等价于:


TIM_SetLoad2(TIMER0, SYS_GetPclkFreq() / 1000000 * 500000);

TIM_SetSize2(TIMER0, TIMER_SIZE_32);

TIM_SetMode2(TIMER0, TIMER_MODE_PERIODIC);

TIM_SetPrescaler2(TIMER0, TIMER_PRESCALE_1);

TIM_EnableInt2(TIMER0);

TIM_EnableTimer2(TIMER0);


以上几个函数中,

TIM_SetPrescaler2 是设置分频,

  三个参数可选:TIMER_PRESCALE_1/TIMER_PRESCALE_16/TIMER_PRESCALE_256

  分别表示分频数:1分频,16分频,256分频;

TIM_SetSize2 设置计时器位宽,

  两个参数可选:TIMER_SIZE_32/TIMER_SIZE_16

  表示计数器的load的位宽是32位还是16位。

TIM_SetLoad2 设置触发时间(以tick为单位)

  如果定时单位为ms,则需要将tick转为ms:SYS_GetPclkFreq()/1000000*ms

中断函数:void TIMER0_isr()

函数说明:该函数为TIMER0的中断函数;

在该函数中需要先查询是第一个还是第二个定时器,然后再清中断。

该中断函数已默认关联,不需要程序中来手工设置。

完整代码样例请参考example下example_timer.c。


六、gpTimer的使用:

General Purpose Timer,即通用计时器。相当于ST中的Advanced Timer.

AG32中包含5个通用计时器(GpTimer),

代码中分别对应:GPTIMER0、GPTIMER1、GPTIMER2...

通用定时器可以实现更多功能,包括:计时、生成pwm、生成任意波形、输入捕获。

5个定时器均可独立设置。

每个定时器支持4个独立通道(channel):

-- 输入捕获

-- PWM输出(边缘或中间对齐模式)

-- 单脉冲输出

主要函数:GPTIMER_Init / GPTIMER_OC_Init.


1、用于简单定时

用于简单定时,只需要关注一个函数:GPTIMER_Init,

设置好参数后,启动计时即可。

举例:

用gpTimer1产生2秒一次的定时。

2


这里使用到的中断函数GPTIMER1_isr,已被SDK自动设置。


2、用于pwm输出

用于pwm输出时,要设置两个函数:GPTIMER_Init 和 GPTIMER_OC_Init。

GPTIMER_Init中设置多长时间触发一次timer;

GPTIMER_OC_Init中指定pwm输出通道及设置pwm的占空比;

举例:

用gpTimer4在通道0上产生pwm输出。


3


除了上述的代码控制外,还需要在ve中添加映射关系:


4


这样的情况下,pwm才会输出到管脚上。

典型案例:呼吸灯(用timer+timerPWM来控制led灯逐渐变量逐渐变暗)


3、输出反向PWM(带死区)

样例程序,请参考网盘下“其他文档\驱动样例补充\example_gptimer_pwm_N.c”


4、输出任意波形

如果要输出的不是pwm的规则波形,而是不规则波形(比如正弦波),则可借助于DMA方式来模拟实现。

思路:事先在数组中定义好数据序列,然后通过dma每次搬运,作用到输出。

这部分功能,参考例程函数:TestGpTimerDma

这种方式也同样需要管脚映射。


5、用于输入捕获

用于输入捕获时,要设置两个函数:GPTIMER_Init 和 GPTIMER_IC_Init。

样例程序,请参考网盘下“其他文档\驱动样例补充\example_gptimer_capture.c”


七、Uart的使用

AG32可用的UART有5个,分别对应UART0、UART1、UART2、UART3、UART4。几个Uart的功能和用法是完全相同的。

样例工程中,UART0被做为输出log的串口。其他几个UART可被用户直接使用。

串口使用较为简单,这里讲述下几个重要函数:

初始化函数:

void UART_Init(UART_TypeDef *uart, UART_BaudRateTypeDef baudrate, UART_LCR_DataBitsTypeDef databits,

        UART_LCR_StopBitsTypeDef stopbits, UART_LCR_ParityTypeDef parity, UART_LCR_FifoTypeDef fifo)

参数说明:

  • Uart:UART0、UART1、UART2、UART3 or UART4

  • Baudrate:波特率,如 115200

  • Databits/stopbits/parity:

  • Fifo:是否开启16字节的fifo缓冲

收发函数:

  • UART_Send(UART_TypeDef *uart, const unsigned char *p, unsigned int num)

  • UART_Receive(UART_TypeDef *uart, unsigned char *p, unsigned int num, unsigned int timeout)

  • 收函数的timeout,是如果收不满num个字符,就等待多少个tick。可以为0。


样例1、实现Uart1的简单收发

  1. 增加ve对uart1的管脚配置:


5


代码中实现如下:


6


样例2、使用接收中断(8字节)来收取数据

这种方式,是使用了FIFO的收中断;(可配置 收到2/4/8/12/16 bytes时触发中断)

代码部分可参考以下方式(新增的红框代码):

7


中断函数UART1_isr在SDK中已经默认关联,不用手动设置。

在中断函数中,要判别中断来源再继续操作。

上例中,收FIFO因为设置为16字节,半数触发时,收到8个字节就会触发中断。


样例3、使用接收中断(1字节)来收取数据

相比样例2,如果想要来1个字节就触发一次中断,可以使用这里的方式。

代码方面:在UART_Init中设置参数为UART_LCR_FIFO_1,并且不用再调UART_SetRxIntFifoLevel函数。


8


样例4、使用DMA收发

如果要启用DMA功能,参考sdk中自带的样例。

需要增加3个函数:

DMAC_Init:启动dma

UART_SetDmaMode:设置只要收/发dma,或收发都要dma

DMAC_Config:设置dma的详细参数。


如果收发都要dma,则需要调用2次DMAC_Config来分别设置。

函数DMAC_Config的参数说明:

void DMAC_Config(

    DMAC_ChannelNumTypeDef channel, //DMA通道

    uint32_t srcAddr, //DMA数据源地址

    uint32_t dstAddr, //DMA数据目标地址

    DMAC_AddrIncTypeDef srcIncr, //传输后源地址是否自增

    DMAC_AddrIncTypeDef dstIncr, //传输后目标地址是否自增

    DMAC_WidthTypeDef srcWidth,  //源地址传输数据的字节宽度(可选8/16/32)

    DMAC_WidthTypeDef dstWidth,  //目标地址传输数据的字节宽度(可选8/16/32)

    DMAC_BurstTypeDef srcBurst,  //源地址一次传输多少

    DMAC_BurstTypeDef dstBurst,

    uint32_t transferSize,   //传输多少次

    DMAC_FlowControlTypeDef transferType, //传输方向类型(8种)

    uint32_t srcPeripheral,      //源地址的外设类型

    uint32_t dstPeripheral      //目标地址的外设类型

)

比如,设置收DMA,会设置参数如:

DMAC_Config(DMAC_CHANNEL1,

    (uint32_t)&UART3->DR, //串口数据寄存器

    (uint32_t)rxbuf,     //收缓冲buff

    DMAC_ADDR_INCR_OFF,    //源地址不自增

    DMAC_ADDR_INCR_ON,     //目标地址自增

    DMAC_WIDTH_8_BIT,      //源数据宽度以8bit为单位

    DMAC_WIDTH_8_BIT,     //目标数据宽度以8bit为单位

    DMAC_BURST_1,

    DMAC_BURST_1,

    0,                    //传输多少次,如果是0则无限制

    DMAC_PERIPHERAL_TO_MEM_PERIPHERAL_CTRL, //外设到内存的方向

    UART3_RX_DMA_REQ,      //源数据外设类型

    0 );                  //目标数据外设类型

设置发的DMA,会设置参数如:

DMAC_Config(DMAC_CHANNEL0,

    (uint32_t)txbuf,      //发缓冲

    (uint32_t)&UART3->DR, //串口数据寄存器

    DMAC_ADDR_INCR_ON,     //发缓冲自增

    DMAC_ADDR_INCR_OFF,    //寄存器不自增

    DMAC_WIDTH_8_BIT,     //源数据宽度以8bit为单位

    DMAC_WIDTH_8_BIT,     //目标数据宽度以8bit为单位

    DMAC_BURST_1,

    DMAC_BURST_1,

    dma_count,            //要传输的数据量

    DMAC_MEM_TO_PERIPHERAL_DMA_CTRL, //内存到外设的方向

    0,                //源数据外设类型

    tx_dma_req);           //目标数据外设类型

以上完整代码样例请参考example部分。


更多样例,请参考网盘

1).dma中断:“其他文档\驱动样例补充\example_uart_dmaIrq.c”

2).闲时中断:“其他文档\驱动样例补充\example_uart_rcvIqr.c”



八、IIC的使用

AG32支持两路I2C,分别对应:I2C0、I2C1;

I2C是一种简单的双向两线制总线协议,半双工,支持多主从模式。I2C最大的特点之一就是有完善的应答机制。

MCU端是I2C的主端。

样例程序参考example_i2c.c

在使用I2C时的流程:

1. Ve中先配置对应的引脚:


9


2. 代码中时钟使能、中断使能、设置频率;


10


3. 使能I2C;


11


4. 收发数据;

   IIC的收过程和发过程,都有对应的应答流程,启动->收/发->结束。

   使用中,收发函数会被完整的封装。

   请参考例程函数(函数流程可参考,封装请自行调整):

   bool I2cReadPROM(uint8_t *mem, bool verify)

   bool I2cWritePROM(uint8_t *mem)


5. 关闭I2C:

12


另外,例程中还使用到了中断函数。当I2C准备好时,会触发该中断。

注意,IIC例程需要接入设备才能测通,否则在I2C_WaitForTransfer函数中会因为等不到Ack而卡住。

.

九、CAN的使用

AG32支持1路CAN,对应:CAN0

样例程序参考example_can.c

在使用CAN时的流程:

  1. ve中先配置对应的引脚:


13


2. 代码中使能时钟、开中断:


14


3. 配置参数(参数较多)并开启can、开启收中断:


15


4. 发送数据:


16


 5. 在中断函数中接收数据:


17


使用时,请参考样例修改。



联系海振远科技

电话:0755-2780 9180;  15323895320;

邮箱: tech@hizyuan.com

Lucy@hizyuan.com