嵌入式综合实验

实验器材

stm32f103c8t6,stlink

实验目的

综合使用实验开发板上的四个led和usart串口,结合前面学习的gpio、定时器、usart等知识,设计综合实验

实验内容

实现功能:上位机通过usart通信控制由定时器中断驱动的led灯切换不同闪烁模式,并实现简单的命令提示功能

应用场景是需要实时手动调整运行参数的环境,通过串口通信可以实时调参,极大避免了每次更新程序参数再烧录的繁琐流程和时间的浪费。

实现代码

cpp 复制代码
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "misc.h"
#include "stdio.h"
#include "stm32f10x_usart.h"
uint16_t dat = 'h'; // 保存接收到的数据
int led_state = 0;  // led状态
  
void gpio_init(void);
void TIM2_Configuration(void);
void USART1_Config(void);
void LED_POWER1(int k);
void LED_POWER2(int k);
void LED_POWER3(int k);
void LED_POWER(int k);
void INFO();
int main(void)
{
    gpio_init();          // GPIO 初始化
    USART1_Config();      // 配置 USART1
    TIM2_Configuration(); // 配置定时器
    // printf("Please Input string ! \r\n"); // 开机后提示输入字符串
    for (;;)
        ;
}
void gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure; // 定义一个 GPIO 初始化类型结构体
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    // 开启 AFIO 时钟和 GPIOB\A 的外设时钟
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);                         // 禁用 JTAG 功能
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_4; // 选择要控制的 GPIOB 引脚
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                // 设置引脚速率为 50MHz
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                                 // 设置引脚模式为通用推挽输出
    GPIO_Init(GPIOB, &GPIO_InitStructure);                                           // 调用库函数,初始化 GPIOB

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;       // 选择要控制的 GPIOA 引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 用作串口输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 用作串口输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void TIM2_Configuration(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;              // 定义一个定时器初始化参数结构体
    NVIC_InitTypeDef NVIC_InitStructure;                        // 定义 NVIC 初始化结构体
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);        // 开启 APB1 的 TIM2 外设时钟
    TIM_DeInit(TIM2);                                           // 将外设 TIM2 的寄存器重设为缺省值
    TIM_TimeBaseStructure.TIM_Prescaler = (7200 - 1);           // 设置预分频系数为(7200-1)
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
    TIM_TimeBaseStructure.TIM_Period = 10000;                   // 自动加载值设置,累计 10000 个时钟周期(1s)后溢出
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);             // 根据 TIM_TimeBaseStructure 中指定的参数初始化 TIM2 里的相关寄存器
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);                       // 清除溢出中断标志
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);                  // 使能 TIM2 中断,允许更新中断
    TIM_Cmd(TIM2, ENABLE);                                      // 使能 TIM2 外设

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);           // 选择中断优先级分组 0
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;           // 选择配置 TIM2 全局中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级为 0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;        // 响应优先级为 1
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           // 使能 TIM2 中断通道
    NVIC_Init(&NVIC_InitStructure);                           // 根据以上配置初始化 NVIC
}
void LED_POWER1(int k)
{
    switch (k)
    {
    case 0:
        GPIO_ResetBits(GPIOB, GPIO_Pin_4);
        GPIO_SetBits(GPIOB, GPIO_Pin_7);
        break;
    case 1:
        GPIO_ResetBits(GPIOB, GPIO_Pin_5);
        GPIO_SetBits(GPIOB, GPIO_Pin_4);
        break;

    case 2:
        GPIO_ResetBits(GPIOB, GPIO_Pin_6);
        GPIO_SetBits(GPIOB, GPIO_Pin_5);
        break;
    case 3:
        GPIO_ResetBits(GPIOB, GPIO_Pin_7);
        GPIO_SetBits(GPIOB, GPIO_Pin_6);
        break;
    default:
        break;
    }
}
void LED_POWER2(int k)
{
    switch (k)
    {
    case 0:
        GPIO_ResetBits(GPIOB, GPIO_Pin_7);
        GPIO_SetBits(GPIOB, GPIO_Pin_4);
        break;
    case 1:
        GPIO_ResetBits(GPIOB, GPIO_Pin_6);
        GPIO_SetBits(GPIOB, GPIO_Pin_7);
        break;

    case 2:
        GPIO_ResetBits(GPIOB, GPIO_Pin_5);
        GPIO_SetBits(GPIOB, GPIO_Pin_6);
        break;
    case 3:
        GPIO_ResetBits(GPIOB, GPIO_Pin_4);
        GPIO_SetBits(GPIOB, GPIO_Pin_5);
        break;
    default:
        break;
    }
}
void LED_POWER3(int k)
{
    k %= 2;
    switch (k)
    {
    case 0:
        GPIO_ResetBits(GPIOB, GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_4);
        break;
    case 1:
        GPIO_SetBits(GPIOB, GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_4);
        break;
    default:
        break;
    }
}
void INFO(void)
{
    printf("creart by cyx 225211 & zxh 225350\r\n");
}
void LED_POWER(int k)
{
    switch (dat)
    {
    case '0':
        LED_POWER1(k);
        break;
    case '1':
        LED_POWER2(k);
        break;
    case '2':
        LED_POWER3(k);
        break;
    case '3':
        GPIO_ResetBits(GPIOB, GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_4);
        break;
    case '4':
        GPIO_SetBits(GPIOB, GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5 | GPIO_Pin_4);
        break;
    case '5':
        printf("info\r\n");
        INFO();
        dat = '4';
        break;
    case 'h':
        printf("0  Forward flashing\r\n1  reverse flashing\r\n2  flashing\r\n3  constant lighting\r\n4  off\r\n5  info\r\n");
        dat = '4';
        break;
    default:
        printf("default model !\r\nprass 'h' for help......\r\n");
        dat = '4';
        break;
    }
}
void TIM2_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) // 1S 时间到,检测到 TIM2 中断
    {
        led_state++;               // 状态加 1
        led_state = led_state % 4; // 取模,状态循环从 0 到 4
        LED_POWER(led_state);      // 控制 LED 状态
        

        TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update); // 清除中断标志位
    }
}
int fputc(int ch, FILE *f) // 重定向 printf()函数
{
    USART_SendData(USART1, (unsigned char)ch);
    // 将 printf()中的内容发往串口
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
    // 发送数据寄存器非空时,循环等待
    {
    }
    return (int)ch; // 返回值
}
void USART1_Config(void)
{
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // 开启 USART1 和 USART1 中断时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_AFIO, ENABLE);

    // 配置 USART1 参数
    USART_InitStructure.USART_BaudRate = 115200;
    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_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

    // 初始化 USART1
    USART_Init(USART1, &USART_InitStructure);


    // 使能 USART1
    USART_Cmd(USART1, ENABLE);

    // 配置 USART1 中断优先级
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);           // 设置NVIC优先级分组
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;         // USART1 中断通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;        // 子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;           // 使能中断
    NVIC_Init(&NVIC_InitStructure);                           // 初始化NVIC

    // 使能 USART1 中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 使能 USART1 接收中断
}
void USART1_IRQHandler(void)
{
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) // 检查接收中断标志
    {
        dat = USART_ReceiveData(USART1); // 读取接收到的数据

        // 清除接收中断标志
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

说在最后,其实代码由可以改进的空间(其实就是懒得改,一开始写的时候有点赶,就没有想那么多)

可以把led控制函数在主函数调用,在定时器中断里调用时,如果串口传来控制信息,最坏情况需要1s才能实现模式改变(定时器设的1s),放到主函数调用就可以及时响应模式改变了。

相关推荐
cherub.3 分钟前
深入解析信号量:定义与环形队列生产消费模型剖析
linux·c++
暮色_年华17 分钟前
Modern Effective C++item 9:优先考虑别名声明而非typedef
c++
重生之我是数学王子25 分钟前
QT基础 编码问题 定时器 事件 绘图事件 keyPressEvent QT5.12.3环境 C++实现
开发语言·c++·qt
日晨难再29 分钟前
嵌入式:STM32的启动(Startup)文件解析
stm32·单片机·嵌入式硬件
我们的五年1 小时前
【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
linux·c++·学习
yufengxinpian1 小时前
集成了高性能ARM Cortex-M0+处理器的一款SimpleLink 2.4 GHz无线模块-RF-BM-2340B1
单片机·嵌入式硬件·音视频·智能硬件
做人不要太理性1 小时前
【C++】深入哈希表核心:从改造到封装,解锁 unordered_set 与 unordered_map 的终极奥义!
c++·哈希算法·散列表·unordered_map·unordered_set
程序员-King.1 小时前
2、桥接模式
c++·桥接模式
chnming19871 小时前
STL关联式容器之map
开发语言·c++
程序伍六七2 小时前
day16
开发语言·c++