五、Base Timer的使用:
六、gpTimer的使用:
1、用于简单定时
2、用于pwm输出
3、输出反向PWM(带死区)
4、输出任意波形
5、用于输入捕获
七、Uart的使用
八、IIC的使用
九、CAN的使用
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的循环定时:
中断函数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。
General Purpose Timer,即通用计时器。相当于ST中的Advanced Timer.
AG32中包含5个通用计时器(GpTimer),
代码中分别对应:GPTIMER0、GPTIMER1、GPTIMER2...
通用定时器可以实现更多功能,包括:计时、生成pwm、生成任意波形、输入捕获。
5个定时器均可独立设置。
每个定时器支持4个独立通道(channel):
-- 输入捕获
-- PWM输出(边缘或中间对齐模式)
-- 单脉冲输出
主要函数:GPTIMER_Init / GPTIMER_OC_Init.
用于简单定时,只需要关注一个函数:GPTIMER_Init,
设置好参数后,启动计时即可。
举例:
用gpTimer1产生2秒一次的定时。
这里使用到的中断函数GPTIMER1_isr,已被SDK自动设置。
用于pwm输出时,要设置两个函数:GPTIMER_Init 和 GPTIMER_OC_Init。
GPTIMER_Init中设置多长时间触发一次timer;
GPTIMER_OC_Init中指定pwm输出通道及设置pwm的占空比;
举例:
用gpTimer4在通道0上产生pwm输出。
除了上述的代码控制外,还需要在ve中添加映射关系:
这样的情况下,pwm才会输出到管脚上。
典型案例:呼吸灯(用timer+timerPWM来控制led灯逐渐变量逐渐变暗)
样例程序,请参考网盘下“其他文档\驱动样例补充\example_gptimer_pwm_N.c”
如果要输出的不是pwm的规则波形,而是不规则波形(比如正弦波),则可借助于DMA方式来模拟实现。
思路:事先在数组中定义好数据序列,然后通过dma每次搬运,作用到输出。
这部分功能,参考例程函数:TestGpTimerDma
这种方式也同样需要管脚映射。
用于输入捕获时,要设置两个函数:GPTIMER_Init 和 GPTIMER_IC_Init。
样例程序,请参考网盘下“其他文档\驱动样例补充\example_gptimer_capture.c”
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的简单收发
增加ve对uart1的管脚配置:
代码中实现如下:
样例2、使用接收中断(8字节)来收取数据
这种方式,是使用了FIFO的收中断;(可配置 收到2/4/8/12/16 bytes时触发中断)
代码部分可参考以下方式(新增的红框代码):
中断函数UART1_isr在SDK中已经默认关联,不用手动设置。
在中断函数中,要判别中断来源再继续操作。
上例中,收FIFO因为设置为16字节,半数触发时,收到8个字节就会触发中断。
样例3、使用接收中断(1字节)来收取数据
相比样例2,如果想要来1个字节就触发一次中断,可以使用这里的方式。
代码方面:在UART_Init中设置参数为UART_LCR_FIFO_1,并且不用再调UART_SetRxIntFifoLevel函数。
样例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”
AG32支持两路I2C,分别对应:I2C0、I2C1;
I2C是一种简单的双向两线制总线协议,半双工,支持多主从模式。I2C最大的特点之一就是有完善的应答机制。
MCU端是I2C的主端。
样例程序参考example_i2c.c
在使用I2C时的流程:
1. Ve中先配置对应的引脚:
2. 代码中时钟使能、中断使能、设置频率;
3. 使能I2C;
4. 收发数据;
IIC的收过程和发过程,都有对应的应答流程,启动->收/发->结束。
使用中,收发函数会被完整的封装。
请参考例程函数(函数流程可参考,封装请自行调整):
bool I2cReadPROM(uint8_t *mem, bool verify)
bool I2cWritePROM(uint8_t *mem)
5. 关闭I2C:
另外,例程中还使用到了中断函数。当I2C准备好时,会触发该中断。
注意,IIC例程需要接入设备才能测通,否则在I2C_WaitForTransfer函数中会因为等不到Ack而卡住。
.
AG32支持1路CAN,对应:CAN0
样例程序参考example_can.c
在使用CAN时的流程:
ve中先配置对应的引脚:
2. 代码中使能时钟、开中断:
3. 配置参数(参数较多)并开启can、开启收中断:
4. 发送数据:
5. 在中断函数中接收数据:
使用时,请参考样例修改。
联系海振远科技
电话:0755-2780 9180; 15323895320;
邮箱: tech@hizyuan.com
Lucy@hizyuan.com