SUPER COW 2024-10-20 20:55 采纳率: 0%
浏览 6

stm32单片机proteus仿真

img


(1)控制2个LED,1个LED亮,1个LED熄灭;
(2)使用定时器控制(1)中2个LED亮灭状态翻转,间隔1秒;
(3)使用串口接收数字0-9,并用以控制PWM模块输出频率为1K-10K启动及停止,并用示波器检测;
(4)使用中断按键启动控制ADC转换;
(5)使用ADC测量光敏电阻LDR阻值,并使用串口显示。
用STM32F103R6实现上述这些功能,用的Proteus仿真,麻烦大家帮忙看看代码和电路连接有没有什么问题


#include "stm32f10x.h"
#include "stdio.h"

// LED 相关定义
#define LED1_GPIO_PORT GPIOB
#define LED1_GPIO_PIN GPIO_Pin_0
#define LED2_GPIO_PORT GPIOB
#define LED2_GPIO_PIN GPIO_Pin_1

// PWM 相关定义
#define PWM_TIMER TIM2
#define PWM_CHANNEL TIM_Channel_1
#define PWM_GPIO_PORT GPIOA
#define PWM_GPIO_PIN GPIO_Pin_0

// 串口相关定义
#define USARTx USART1
#define USART_RX_PIN GPIO_Pin_10
#define USART_TX_PIN GPIO_Pin_9
#define USART_GPIO_PORT GPIOA

// 频率范围
#define MIN_FREQUENCY 1000
#define MAX_FREQUENCY 10000

// 当前频率变量
volatile uint32_t currentFrequency = MIN_FREQUENCY;

// 标志位,表示 PWM 是否正在运行
volatile uint8_t pwmRunning = 1;

// ADC 相关定义
#define ADC_CHANNEL ADC_Channel_1
#define ADC_GPIO_PORT GPIOA
#define ADC_GPIO_PIN GPIO_Pin_1

// 中断按键相关定义
#define KEY_GPIO_PORT GPIOC
#define KEY_PIN GPIO_Pin_0
#define KEY_EXTI_LINE EXTI_Line0
#define KEY_IRQn EXTI0_IRQn

// 光敏电阻相关参数
#define REFERENCE_RESISTANCE 10000.0 // 参考电阻值,单位欧姆

void GPIO_Config(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIOMode_TypeDef GPIO_Mode)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOx, &GPIO_InitStructure);
}

void USART1_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);

    GPIO_Config(USART_GPIO_PORT, USART_TX_PIN | USART_RX_PIN, GPIO_Mode_AF_PP);

    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_Init(USARTx, &USART_InitStructure);

    USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);

    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    USART_Cmd(USARTx, ENABLE);
}

void USART_SendChar(char ch)
{
    while (!(USARTx->SR & USART_FLAG_TXE));
    USART_SendData(USARTx, ch);
}

void USART_SendString(const char* str)
{
    while (*str)
    {
        USART_SendChar(*str++);
    }
}

int fputc(int ch, FILE *f)
{
    USART_SendChar((char)ch);
    return ch;
}

void LED_Toggle(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
    GPIOx->ODR ^= GPIO_Pin;
    USART_SendString("LED toggled.\n");
}

void LED_Init(void)
{
    GPIO_Config(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_Mode_Out_PP);
    GPIO_Config(LED2_GPIO_PORT, LED2_GPIO_PIN, GPIO_Mode_Out_PP);

    // 初始状态 LED1 亮,LED2 灭
    GPIO_ResetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);
    GPIO_SetBits(LED2_GPIO_PORT, LED2_GPIO_PIN);
    USART_SendString("LED_Init\n");
}

void Timer3_Init(void)
{
    USART_SendString("Starting Timer3 initialization...\n");
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_TimeBaseStructure.TIM_Period = 9999;
    TIM_TimeBaseStructure.TIM_Prescaler = 7199;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    TIM_Cmd(TIM3, ENABLE);
    USART_SendString("Timer3_Init\n");
    USART_SendString("Timer3 initialization completed.\n");
}

void TIM3_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM3, TIM_IT_Update)!= RESET)
    {
        USART_SendString("Timer3 counter value before LED toggle: ");
        char buffer[64];
        snprintf(buffer, sizeof(buffer), "%d\n", TIM3->CNT);
        USART_SendString(buffer);
        LED_Toggle(LED1_GPIO_PORT, LED1_GPIO_PIN);
        LED_Toggle(LED2_GPIO_PORT, LED2_GPIO_PIN);
        USART_SendString("Timer3 counter value after LED toggle: ");
        snprintf(buffer, sizeof(buffer), "%d\n", TIM3->CNT);
        USART_SendString(buffer);

        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
        USART_SendString("Timer3 interrupt occurred.\n");
    }
}

void PWM_Init(void)
{
    USART_SendString("Starting PWM initialization...\n");
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_Config(PWM_GPIO_PORT, PWM_GPIO_PIN, GPIO_Mode_AF_PP);

    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / currentFrequency - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = 0;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(PWM_TIMER, &TIM_TimeBaseStructure);

    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = TIM_TimeBaseStructure.TIM_Period / 2;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OC1Init(PWM_TIMER, &TIM_OCInitStructure);
    TIM_OC1PreloadConfig(PWM_TIMER, TIM_OCPreload_Enable);

    TIM_Cmd(PWM_TIMER, ENABLE);
    USART_SendString("PWM_Init\n");
    USART_SendString("PWM initialization completed. Period: ");
    char buffer[32];
    snprintf(buffer, sizeof(buffer), "%d\n", TIM_TimeBaseStructure.TIM_Period);
    USART_SendString(buffer);
}

void USART1_IRQHandler(void)
{
    if (USART_GetITStatus(USARTx, USART_IT_RXNE)!= RESET)
    {
        char receivedChar = USART_ReceiveData(USARTx);
        uint8_t receivedNumber = receivedChar - '0';

        if (receivedNumber >= 0 && receivedNumber <= 9)
        {
            currentFrequency = MIN_FREQUENCY + receivedNumber * (MAX_FREQUENCY - MIN_FREQUENCY) / 9;
            TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
            TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / currentFrequency - 1;
            TIM_TimeBaseInit(PWM_TIMER, &TIM_TimeBaseStructure);
            TIM_SetAutoreload(PWM_TIMER, TIM_TimeBaseStructure.TIM_Period);
            USART_SendString("Updated PWM frequency.\n");
        }
        else if (receivedChar == 's')
        {
            pwmRunning =!pwmRunning;
            if (pwmRunning)
            {
                TIM_Cmd(PWM_TIMER, ENABLE);
                USART_SendString("PWM started.\n");
            }
            else
            {
                TIM_Cmd(PWM_TIMER, DISABLE);
                USART_SendString("PWM stopped.\n");
            }
        }
        USART_ClearITPendingBit(USARTx, USART_IT_RXNE);
    }
}

// 中断按键中断处理函数
void KEY_IRQHandler(void)
{
    if (EXTI_GetITStatus(KEY_EXTI_LINE)!= RESET)
    {
        // 启动 ADC 转换
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);
        USART_SendString("Key pressed, starting ADC conversion.\n");
        EXTI_ClearITPendingBit(KEY_EXTI_LINE);
    }
}

// 读取 ADC 值函数
uint16_t readADCValue(ADC_TypeDef* ADCx)
{
    ADC_SoftwareStartConvCmd(ADCx, ENABLE);
    while (!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC));
    return ADC_GetConversionValue(ADCx);
}

// 计算光敏电阻阻值函数
float calculateLDRResistance(uint16_t adcValue)
{
    // 假设 ADC 参考电压为 3.3V
    float adcVoltage = adcValue * 3.3 / 4095.0;
    float ldrVoltage = 3.3 - adcVoltage;
    return REFERENCE_RESISTANCE * adcVoltage / ldrVoltage;
}

int main(void)
{
    USART1_Init();
    LED_Init();
    Timer3_Init();
    PWM_Init();

    ADC_InitTypeDef adcInitStruct;
    adcInitStruct.ADC_Mode = ADC_Mode_Independent;
    adcInitStruct.ADC_ScanConvMode = DISABLE;
    adcInitStruct.ADC_ContinuousConvMode = DISABLE;
    adcInitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    adcInitStruct.ADC_DataAlign = ADC_DataAlign_Right;
    adcInitStruct.ADC_NbrOfChannel = 1;

    ADC_Init(ADC1, &adcInitStruct);

    // 配置中断按键
    GPIO_Config(KEY_GPIO_PORT, KEY_PIN, GPIO_Mode_IPU);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource0);
    EXTI_InitTypeDef EXTI_InitStructure;
    EXTI_InitStructure.EXTI_Line = KEY_EXTI_LINE;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    NVIC_InitTypeDef NVIC_InitStructureKey;
    NVIC_InitStructureKey.NVIC_IRQChannel = KEY_IRQn;
    NVIC_InitStructureKey.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructureKey.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructureKey.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructureKey);

    while (1)
    {
        uint16_t adcValue = readADCValue(ADC1);
        float ldrResistance = calculateLDRResistance(adcValue);
        char buffer[64];
        snprintf(buffer, sizeof(buffer), "LDR Resistance: %.2f ohms\n", ldrResistance);
        USART_SendString(buffer);
    }
}
  • 写回答

1条回答 默认 最新

  • 无疆76 2024-10-20 20:56
    关注

    以下回复参考:皆我百晓生券券喵儿等免费微信小程序作答:

    这段代码是使用STM32单片机进行Proteus仿真的一个示例。Proteus是一款电路设计和微控制器模拟软件,可以用于模拟各种电子项目。在这个特定的例子中,代码是用C语言编写的,用于控制STM32F10x系列微控制器的一些功能。下面是关于代码的简要解释:

    1. 包括的头文件: 代码开始时包括了一些必要的头文件,这些文件包含了STM32F10x系列微控制器的寄存器定义和其他必要的定义。
    2. LED相关定义: 定义了一些与LED相关的宏,包括LED所连接的GPIO端口和引脚。
    3. PWM相关定义: 定义了与PWM输出相关的宏,包括定时器、GPIO端口和引脚等。
    4. 串口相关定义: 定义了串口(USART)的相关参数,包括接收和发送的引脚、端口等。
    5. 频率范围定义: 定义了PWM的频率范围。
    6. 中断和标志位定义: 定义了一些中断和标志位,用于控制程序中的中断处理和状态标识。
    7. GPIO配置函数: 一个用于配置GPIO端口的函数,可以设置GPIO的模式、速度和输出类型等。
    8. USART初始化函数: 初始化USART(串口通信)的函数,包括配置波特率、数据位、停止位、校验位等。
    9. 定时器初始化函数: 初始化一个定时器(Timer3),用于产生中断,可以在中断处理函数中执行一些任务,如切换LED的状态。
    10. PWM初始化函数: 初始化PWM(脉宽调制)输出,包括配置定时器、GPIO端口等。
    11. USART中断处理函数: 当USART接收到数据时,会进入此中断处理函数,根据接收到的数据更新PWM的频率或控制PWM的启动/停止。
    12. 按键中断处理函数: 当按键被按下时,会进入此中断处理函数,启动ADC转换。
    13. 读取ADC值函数: 读取ADC(模数转换器)的值。
    14. 计算光敏电阻阻值函数: 根据ADC的值计算光敏电阻的阻值。
    15. 主函数: 在主函数中,进行了各种初始化操作(如USART、LED、定时器、PWM、ADC等),然后进入一个无限循环,不断读取光敏电阻的值并通过串口发送出去。

    总的来说,这段代码的主要功能是使用STM32F10x系列微控制器模拟PWM输出和光敏电阻的读取,并通过串口进行通信。在Proteus仿真软件中,你可以看到LED的闪烁、PWM波形的输出以及光敏电阻的阻值变化。

    评论

报告相同问题?

问题事件

  • 创建了问题 10月20日