打印
[APM32F4]

TMR+DMA输出模拟信号应用

[复制链接]
25|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 宫影空明人不往 于 2025-2-9 22:10 编辑

前言
当芯片可以使用的通讯模块都被占用了,我们该如何去发送相应的通讯信号呢?这时候可以选择使用定时器和DMA来输出特性波形的模拟信号。在现代嵌入式系统和通信领域,定时器(TMR)和直接内存访问(DMA)是两个非常重要的硬件模块。它们可以协同工作,生成特定的波形,模拟其他信号通信协议。
使用场景
1. 模拟通信协议
在许多嵌入式系统中,可能需要模拟某些通信协议,如UART、SPI、I2C等。使用TMR和DMA可以精确地生成这些协议所需的波形,从而在没有硬件支持的情况下实现通信功能。
2. 信号发生器
在测试和调试过程中,可能需要生成特定的信号波形来测试设备的响应。TMR和DMA可以用于生成这些信号,提供高精度和高灵活性的信号输出。
3. 音频信号处理
在音频处理应用中,TMR和DMA可以用于生成特定的音频波形,如正弦波、方波等,用于音频信号的合成和处理。
4. 电机控制
在电机控制应用中,TMR和DMA可以用于生成PWM信号,控制电机的转速和方向。通过精确控制PWM信号的占空比和频率,可以实现对电机的精确控制。
好处
1.高精度
2.低CPU开销
3.灵活性
4.实时性
实现
下面我们将通过一个具体的例子,展示如何使用TMR和DMA模拟UART发送一段特定的字符串。
实现原理
下面的例子利用DMA的突发传输,在定时器产生更新DMA请求时,可以将定时器的多个连续的寄存器进行改变。这里选择将定时器的计数器和比较器的值刷新,从而改变下一段高低电平的时间长度,从而生成特定的信号。
硬件配置
这里我们使用APM32F407开发板,模块使用是定时器8来产生相应的串口信号,DMA2来将数据从内存传输到GPIO端口。
软件实现
1.配置定时器8
    F407的主频是168MHz,定时器8的主频为系统时钟168MHz,这里的话将定时器8分频设置为167。那么定时器8计数器数值加1的波长为1us。同时将定时器8的计数值和比较器值分别设置成999和1000,计数方式上升,极性高电平。那么TMR8将一直输出高电平,直到DMA将其刷新。

    TMR_TimeBaseStruct.clockDivision = TMR_CLOCK_DIV_1;

    TMR_TimeBaseStruct.countMode = TMR_COUNTER_MODE_UP;

    TMR_TimeBaseStruct.division = 167;

    TMR_TimeBaseStruct.period = 999;

    TMR_TimeBaseStruct.repetitionCounter = 0;

    TMR_ConfigTimeBase(TMR8, &TMR_TimeBaseStruct);

...

    TMR_ConfigDMA(TMR8, TMR_DMA_BASE_AUTORLD, TMR_DMA_BURSTLENGTH_3TRANSFERS);

    TMR_EnableDMASoure(TMR8, TMR_DMA_SOURCE_UPDATE);


2.配置DMA2
    根据F4的用户手册,将DMA配置成定时器8的更新触发,目标寄存器为定时器8的DMADDR寄存器。

    DMA_Config_T dmaConfig;

    RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_DMA2);



    dmaConfig.bufferSize = sizeof(ConfigBuf);

    dmaConfig.memoryDataSize = DMA_MEMORY_DATA_SIZE_HALFWORD;

    dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_HALFWORD;

    dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE;

    dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;

    dmaConfig.loopMode = DMA_MODE_CIRCULAR;

    dmaConfig.priority = DMA_PRIORITY_HIGH;

    dmaConfig.dir = DMA_DIR_MEMORYTOPERIPHERAL;

    dmaConfig.memoryBaseAddr = (uint32_t)ConfigBuf;

    dmaConfig.peripheralBaseAddr = (uint32_t)&TMR8->DMADDR;



    dmaConfig.channel = DMA_CHANNEL_7;

    dmaConfig.fifoMode = DMA_FIFOMODE_ENABLE;

    dmaConfig.fifoThreshold = DMA_FIFOTHRESHOLD_FULL;

    dmaConfig.peripheralBurst = DMA_PERIPHERALBURST_SINGLE;

    dmaConfig.memoryBurst = DMA_MEMORYBURST_SINGLE;

    DMA_Config(DMA2_Stream1, &dmaConfig);

    DMA_Enable(DMA2_Stream1);


3.配置数组
    根据需要输出的信号,编写相应的数组。根据定时器的配置,计数器加1时间为1us。那么第一次更新后,DMA将54,0,24分别赋值到定时器8的计数值,重复计数值,比较值。那么输出的信号为为24us的高电平,32us的低电平。定时器更新后产生DMA更新信号,下一组的信号则为8us的高电平,16us的电平。后面则以此类推。这里的话将8us作为一个串口单位,则对于串口波特率为125000。

uint16_t ConfigBuf[120] = {56,0,24,24,0,8 ,16,0,8 ,24,0,16,

                           16,0,8, 24,0,8,24,0,16 ,40,0,16,

                           24,0,16, 24,0,16, 40,0,16,

                           24,0,16, 24,0,16, 24,0,16,

                           40,0,32, 24,0,16, 64,0,16,

                           24,0,8, 24,0,16,

                           32,0,24, 16,0,8, 16,0,8, 24,0,16,

                           40,0,32, 24,0,16, 32,0,16,

                           24,0,8, 32,0,24, 40,0,16,

                           24,0,16, 24,0,16, 40,0,16,

                           24,0,8, 24,0,16,24,0,16,

                           40,0,8, 24,0,8, 999, 0 ,1000};


结果
将定时器8的输出IO引脚接到串口的Rx引脚上,波特率选择125000,8bit,无校验位。复位开发板后,可以看见串口正常接收。

结论
使用TMR和DMA输出特定波形模拟其他信号通信,具有高精度、低CPU开销、灵活性和实时性等优点。通过合理配置TMR和DMA,可以实现各种复杂的信号生成和处理任务,满足不同应用场景的需求。本文通过一个具体的例子,展示了如何使用TMR和DMA模拟125000波特率的UART信号发送,为类似的应用提供了参考。


使用特权

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

本版积分规则

11

主题

12

帖子

0

粉丝