写一段stm32f100cbt6的三个可选的正弦信号,分别是100赫兹,一千赫兹和十千赫兹,并且可以通过一个按钮切换这三个频率
时间: 2024-05-10 18:15:34 浏览: 110
正弦波 实现在10HZ~300HZ的频率可调 C 语言代码
3星 · 编辑精心推荐
以下是一种实现方法,使用定时器 TIM3 和 DAC 输出正弦波:
```c
#include "stm32f10x.h"
#define SAMPLE_RATE 20000 // 采样率,单位为 Hz
#define BUFFER_SIZE SAMPLE_RATE // 缓冲区大小,为一个周期的采样点数
// 正弦波采样表,包含一个周期的采样数据
const uint16_t sine_table[BUFFER_SIZE] = {
2048, 2098, 2148, 2198, 2248, 2298, 2348, 2398, 2447, 2496, 2545, 2593, 2641, 2689, 2736, 2782,
2828, 2873, 2918, 2962, 3005, 3048, 3090, 3131, 3171, 3211, 3249, 3287, 3324, 3360, 3395, 3429,
3462, 3494, 3525, 3555, 3584, 3611, 3638, 3663, 3687, 3710, 3732, 3752, 3771, 3789, 3805, 3821,
3834, 3847, 3858, 3868, 3877, 3884, 3890, 3894, 3897, 3898, 3898, 3897, 3894, 3890, 3884, 3877,
3868, 3858, 3847, 3834, 3821, 3805, 3789, 3771, 3752, 3732, 3710, 3687, 3663, 3638, 3611, 3584,
3555, 3525, 3494, 3462, 3429, 3395, 3360, 3324, 3287, 3249, 3211, 3171, 3131, 3090, 3048, 3005,
2962, 2918, 2873, 2828, 2782, 2736, 2689, 2641, 2593, 2545, 2496, 2447, 2398, 2348, 2298, 2248,
2198, 2148, 2098, 2048, 1997, 1947, 1897, 1847, 1797, 1747, 1697, 1648, 1599, 1550, 1502, 1454,
1406, 1359, 1313, 1267, 1222, 1177, 1133, 1090, 1047, 1005, 964, 923, 883, 844, 805, 768, 731, 695,
660, 625, 591, 557, 525, 493, 462, 432, 403, 375, 348, 321, 296, 271, 248, 225, 204, 183, 164, 145,
128, 111, 96, 81, 68, 55, 44, 33, 24, 15, 8, 3, 0, 0, 0, 3, 8, 15, 24, 33, 44, 55, 68, 81, 96, 111, 128,
145, 164, 183, 204, 225, 248, 271, 296, 321, 348, 375, 403, 432, 462, 493, 525, 557, 591, 625, 660,
695, 731, 768, 805, 844, 883, 923, 964, 1005, 1047, 1090, 1133, 1177, 1222, 1267, 1313, 1359, 1406,
1454, 1502, 1550, 1599, 1648, 1697, 1747, 1797, 1847, 1897, 1947, 1997};
// 当前正弦波频率的索引
volatile uint16_t sine_index = 0;
// 当前正弦波频率的周期
uint16_t sine_period = BUFFER_SIZE;
// 计数器,用于计算采样率
volatile uint32_t counter = 0;
// 按钮状态
volatile uint8_t button_pressed = 0;
// 定时器 TIM3 中断服务函数
void TIM3_IRQHandler(void) {
// 清除更新中断标志位
TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
// 输出 DAC 采样值
DAC_SetChannel1Data(DAC_Align_12b_R, sine_table[sine_index]);
// 更新正弦波索引
sine_index++;
if (sine_index >= sine_period) {
sine_index = 0;
}
// 计算采样率
counter++;
if (counter >= SAMPLE_RATE) {
counter = 0;
GPIO_WriteBit(GPIOB, GPIO_Pin_7, button_pressed ? Bit_SET : Bit_RESET);
}
}
// EXTI0 中断服务函数
void EXTI0_IRQHandler(void) {
// 清除 EXTI0 中断标志位
EXTI_ClearITPendingBit(EXTI_Line0);
// 切换正弦波频率
if (sine_period == BUFFER_SIZE) {
sine_period = SAMPLE_RATE / 10;
} else if (sine_period == SAMPLE_RATE / 10) {
sine_period = SAMPLE_RATE / 100;
} else {
sine_period = BUFFER_SIZE;
}
}
int main(void) {
// 使能 GPIOB 和 AFIO 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
// 使能 TIM3 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
// 使能 DAC 时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
// 配置 PB0 为输入引脚,带上拉
GPIO_InitTypeDef gpio_init;
gpio_init.GPIO_Pin = GPIO_Pin_0;
gpio_init.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(GPIOB, &gpio_init);
// 配置 PB7 为输出引脚,用于指示按钮状态
gpio_init.GPIO_Pin = GPIO_Pin_7;
gpio_init.GPIO_Mode = GPIO_Mode_Out_PP;
gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio_init);
// 配置 PB4 为 DAC 输出引脚
gpio_init.GPIO_Pin = GPIO_Pin_4;
gpio_init.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOB, &gpio_init);
// 配置 DAC 通道 1
DAC_InitTypeDef dac_init;
dac_init.DAC_Trigger = DAC_Trigger_T3_TRGO;
dac_init.DAC_WaveGeneration = DAC_WaveGeneration_None;
dac_init.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;
dac_init.DAC_OutputBuffer = DAC_OutputBuffer_Enable;
DAC_Init(DAC_Channel_1, &dac_init);
// 使能 DAC 通道 1
DAC_Cmd(DAC_Channel_1, ENABLE);
// 配置 TIM3
TIM_TimeBaseInitTypeDef tim_init;
tim_init.TIM_Period = (SystemCoreClock / SAMPLE_RATE) - 1;
tim_init.TIM_Prescaler = 0;
tim_init.TIM_ClockDivision = TIM_CKD_DIV1;
tim_init.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &tim_init);
// 配置 TIM3 更新事件触发中断,启动定时器
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM3, ENABLE);
// 配置 EXTI0 中断线路
EXTI_InitTypeDef exti_init;
exti_init.EXTI_Line = EXTI_Line0;
exti_init.EXTI_Mode = EXTI_Mode_Interrupt;
exti_init.EXTI_Trigger = EXTI_Trigger_Rising;
exti_init.EXTI_LineCmd = ENABLE;
EXTI_Init(&exti_init);
// 配置 NVIC 中断优先级
NVIC_InitTypeDef nvic_init;
nvic_init.NVIC_IRQChannel = TIM3_IRQn;
nvic_init.NVIC_IRQChannelPreemptionPriority = 0;
nvic_init.NVIC_IRQChannelSubPriority = 0;
nvic_init.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic_init);
nvic_init.NVIC_IRQChannel = EXTI0_IRQn;
nvic_init.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_Init(&nvic_init);
while (1) {
// 读取按钮状态
button_pressed = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0);
}
}
```
该程序使用 PB0 作为按钮输入引脚,PB7 作为按钮状态输出引脚,PB4 作为 DAC 输出引脚。在 TIM3 的更新中断服务函数中,每次输出正弦波的一个采样点,并根据当前正弦波频率的周期更新正弦波索引。在 EXTI0 中断服务函数中,根据按钮状态切换正弦波频率的周期。程序中使用了一个正弦波采样表,包含了一个周期的采样数据,通过改变正弦波的周期来改变正弦波的频率。在输出 DAC 时,使用 DAC_Align_12b_R 对齐方式,将采样值右移 4 位,变成 12 位数据。
阅读全文