基于GD32F303RCT6芯片 通过PWM与DMA结合硬件控制呼吸灯,用C语言写一份代码
时间: 2023-05-26 20:01:25 浏览: 343
以下是基于GD32F303RCT6芯片的PWM与DMA结合硬件控制呼吸灯的C语言代码示例:
```
#include "gd32f30x.h"
#define LED_PIN GPIO_PIN_5
#define LED_PORT GPIOB
#define PWM_CHANNEL TIMER_CH_1
#define PWM_FREQ 1000
#define LED_MAX_BRIGHTNESS 200
uint16_t dma_buffer[2];
void init_gpio(void)
{
rcu_periph_clock_enable(RCU_GPIOB);
gpio_init(LED_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, LED_PIN);
}
void init_timer(void)
{
rcu_periph_clock_enable(RCU_TIMER1);
timer_oc_parameter_struct oc_initpara;
timer_parameter_struct timer_initpara;
timer_deinit(TIMER1);
timer_struct_para_init(&timer_initpara);
timer_initpara.prescaler = SystemCoreClock / PWM_FREQ - 1;
timer_initpara.period = LED_MAX_BRIGHTNESS - 1;
timer_initpara.clock_division = TIMER_CKDIV_DIV1;
timer_initpara.align = TIMER_ALIGN_CENTER;
timer_initpara.repetition_counter = 0;
timer_init(TIMER1, &timer_initpara);
timer_channel_output_struct_para_init(&oc_initpara);
oc_initpara.output_compare_mode = TIMER_OC_MODE_PWM1;
oc_initpara.output_polarity = TIMER_OC_POLARITY_HIGH;
oc_initpara.oc_idle_state = TIMER_OC_IDLE_STATE_LOW;
oc_initpara.compare = 0;
timer_channel_output_config(TIMER1, PWM_CHANNEL, &oc_initpara);
timer_channel_output_pulse_value_config(TIMER1, PWM_CHANNEL, 0);
timer_channel_output_mode_config(TIMER1, PWM_CHANNEL, TIMER_OC_MODE_PWM1);
timer_channel_output_shadow_config(TIMER1, PWM_CHANNEL, TIMER_OC_SHADOW_DISABLE);
timer_primary_output_config(TIMER1, ENABLE);
timer_enable(TIMER1);
}
void init_dma(void)
{
dma_parameter_struct dma_initpara;
rcu_periph_clock_enable(RCU_DMA0);
dma_deinit(DMA0, DMA_CH1);
dma_struct_para_init(&dma_initpara);
dma_initpara.direction = DMA_MEMORY_TO_PERIPHERAL;
dma_initpara.memory_addr = (uint32_t)&dma_buffer[0];
dma_initpara.memory_width = DMA_MEMORY_WIDTH_16BIT;
dma_initpara.periph_addr = (uint32_t)&TIMER_CAR(TIMER1);
dma_initpara.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
dma_initpara.number = 2;
dma_initpara.priority = DMA_PRIORITY_HIGH;
dma_initpara.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_initpara.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_initpara.circular_mode = DMA_CIRCULAR_MODE_ENABLE;
dma_initpara.periph_handshake = DMA_REQUEST_5;
dma_initpara.channel = DMA_CH1;
dma_init(DMA0, DMA_CH1, &dma_initpara);
dma_circulation_enable(DMA0, DMA_CH1);
dma_memory_to_periph_mode_enable(DMA0, DMA_CH1);
dma_channel_enable(DMA0, DMA_CH1);
}
void update_led_brightness(uint8_t brightness)
{
dma_buffer[0] = (uint16_t)LED_MAX_BRIGHTNESS * brightness / 255;
dma_buffer[1] = LED_MAX_BRIGHTNESS - dma_buffer[0];
}
int main(void)
{
init_gpio();
init_timer();
init_dma();
update_led_brightness(0);
while (1) {
for (uint8_t brightness = 0; brightness < 255; brightness++) {
update_led_brightness(brightness);
while (dma_get_flag(DMA0, DMA_CH1, DMA_FLAG_FTF) == RESET);
dma_flag_clear(DMA0, DMA_CH1, DMA_FLAG_FTF);
}
for (uint8_t brightness = 255; brightness > 0; brightness--) {
update_led_brightness(brightness);
while (dma_get_flag(DMA0, DMA_CH1, DMA_FLAG_FTF) == RESET);
dma_flag_clear(DMA0, DMA_CH1, DMA_FLAG_FTF);
}
}
return 0;
}
```
在上面的代码中,我们首先定义了LED的GPIO引脚和端口。然后我们定义了PWM通道和频率,以及LED的最大亮度和DMA缓冲区。
在`init_gpio()`函数中,我们启用LED的GPIO端口并将其配置为复用推挽输出模式。
在`init_timer()`函数中,我们启用并配置计时器1作为PWM控制器,并将其输出连接到LED引脚。我们启用了PWM1模式和高低电平极性,并将占空比零值设置为0。
在`init_dma()`函数中,我们启用并配置DMA0通道1,将其设置为循环模式,并配置其数据方向为从存储器到外设。每次更新LED亮度时,我们将DMA缓冲区的前一半设置为当前亮度值,而将后一半设置为补码亮度值。
在`update_led_brightness()`函数中,我们将当前亮度值转化为计时器1的占空比,并将其写入DMA缓冲区中。
最后在`main()`函数中,我们循环设置LED的亮度值和等待DMA传输完成。通过这种方式,我们可以实现呼吸灯效果。
阅读全文