掘金 后端 ( ) • 2024-05-03 09:56

前言:

从一月十九日写下的草稿箱开始学习51单片机,到现在学习完32。

不知觉已经经历了四个月的时间,简单的调整方向后决定通过一个STM32的小案例进行巩固32的学习。 image.png

这次的案例没有教程,通过自己现有的一些设备来完成这样的一个小实验。代码可能不够高效,方法可能不是很好,却是对自己的一个检验。

知识获取来源于哔哩哔哩江科大的32教程,以及其他UP的视频。

设计思路:

首先从整体来看是一个有三种控制的LED灯,但是不局限于LED灯,可以通过连接其他外设或者继电器来控制更多的设备。整体上来说是一个三模的操控系统。

classDiagram
Butten <|-- AD
Butten <|-- Serial
Butten <|-- Key
Butten : uint8_t KeyNum
Butten : uint8_t Ligh_Detect_Flag
Butten: Butten_Init()
Butten: Butten_Control()
Butten : Butten_Show()
class AD{
AD_Init()
quack()
}
class Serial{
uint8_t RxData_Flag
-canEat()
}
class Key{
Key_Init()
Key_GetNum()
}

主要可以集成到Butten类里,在本身的Butten类中引用了AD、Serial、Key。

  • Butten中主要有三个函数

    • Init()| 进行初始化,包括各个函数的初始化,以及时钟、GPIO、中断、OLED展示的初始化。
    • Control() | 主要对状态机的判断,执行相对应的操作。
    • Show() | 进行OLED功能展示,判断标志位以及GPIO高低电平来显示对应信息。
  • 在Butten中通过Key提供的Key_GetNum()函数来获取按下的键码值,来进行开关灯以及光敏模块的开关操作。

  • 通过引用AD,获取ADC转换后的结果并展示出来,同时配置ADC中模拟看门狗以及对应中断,通过中断的方式来实现天黑自动关灯,天亮自动开灯的功能。

  • 通过引用Serial,配置串口接收中断。在收到蓝牙发送的特定信息来执行相应操作,开关灯以及开关光敏模块的功能。因为用的是HC-08,所以暂时只能用商家提供的蓝牙调试软件,因此暂时没有设计回传状态的功能。

演示

由于掘金平台只能上传西瓜的视频,但是又不想去发布西瓜的视频,因此将视频转换为GIF的格式进行展示,当然观感也会下降,但是可以看出来效果。

按键演示:

按键演示.gif

光敏模块演示:

光敏模块演示.gif

蓝牙演示:

蓝牙演示.gif

具体代码实现:

  • Button
#ifndef __BUTTON_H
#define __BUTTON_H

extern uint8_t KeyNum;
extern uint8_t Light_Detect_Flag;

void Butten_Init(void);
void Butten_Control(void);


#endif 
#include "stm32f10x.h"                  // Device header
#include "LED.h"
#include "Key.h"
#include "OLED.h"
#include "AD.h"
#include "Timer.h"
#include "Serial.h"
#include "../System/Delay.h"

float Data;
uint8_t KeyNum;
uint16_t Data_Temp;
uint8_t Light_Detect_Flag = 1 ;

void Butten_Show(void);
void Light_Detect_Turn(void);


void Butten_Init(void)
{
    LED_Init();
    Key_Init();
	AD_Init();
	Serial_Init();

	OLED_ShowString(1,1,"LED:OFF");
	OLED_ShowString(2,1,"Detect: ON");

}

void Butten_Control(void)
{
    KeyNum = Key_GetNum();

    if (KeyNum == 1 )
    {
        LED0_Turn();
    }
    else if (KeyNum == 2)
    {
       Light_Detect_Turn();
    }
    Butten_Show();

}


void Butten_Show(void)
{
    if (GPIO_ReadOutputDataBit(GPIOA , GPIO_Pin_0) == 1)
    {
    	OLED_ShowString(1,1,"LED:OFF");
    }
    else
    {
    	OLED_ShowString(1,1,"LED: ON");
    }

    if (Light_Detect_Flag == 1)
    {
        OLED_ShowString(2,1,"Detect:OFF");
        OLED_ShowString(3 , 1 , "              " );
    }else if (Light_Detect_Flag == 0)
    {
    	OLED_ShowString(2,1,"Detect: ON");
        Data_Temp = ADC_GetConversionValue(ADC1);
        Data = (float)Data_Temp / 4095 * 100 ;
        
        OLED_ShowNum(3 , 1 , Data, 2);
        OLED_ShowChar(3, 3 ,'%');
        OLED_ShowNum(3 , 5 , (float)(AD_GetLightH() + 100 ) / 4095 * 100 , 2);
        OLED_ShowChar(3, 7 ,'%');
        OLED_ShowNum(3 , 10 , (float)(AD_GetLightL() + 100 ) / 4095 * 100, 2);
        OLED_ShowChar(3, 12 ,'%');
        Delay_ms(100);
    }

    if (RxData_Flag == 1)
    {
        OLED_ShowString(4 ,1 , "LED0-ON");
        Delay_ms(100);
        OLED_ShowString(4, 1, "        ");
        RxData_Flag = 0;
    }
    else if (RxData_Flag == 2)
    {
        OLED_ShowString(4 ,1 , "LED0-OFF");        
        Delay_ms(100);
        OLED_ShowString(4, 1, "        "); 
        RxData_Flag = 0;
    }
    else if (RxData_Flag == 3)
    {
        Light_Detect_Turn();
        RxData_Flag = 0;
    }

}

void Light_Detect_Turn(void)
{
    if (Light_Detect_Flag == 1)
        {
            Light_Detect_Flag = 0 ;
        }else if (Light_Detect_Flag == 0)
        {
            LED0_OFF();
            Light_Detect_Flag = 1 ;
        }
}

void ADC1_2_IRQHandler(void)
{
    if(ADC_GetITStatus(ADC1 , ADC_IT_AWD) == SET)
    {
        
        if (Light_Detect_Flag == 0)
        {
            if (ADC_GetConversionValue(ADC1) < 2000)
            {
                LED0_OFF();
            }
            else if (ADC_GetConversionValue(ADC1) > 3000)
            {
                LED0_ON();
            }
        }

        ADC_ClearITPendingBit(ADC1 , ADC_IT_AWD);
        
    }
    
}
  • Key
#ifndef __KEY_H
#define __KEY_H

void Key_Init(void);
uint8_t Key_GetNum(void);

#endif 
#include "stm32f10x.h"
#include "Delay.h"

void Key_Init()
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11;
    GPIO_Init(GPIOB , &GPIO_InitStructure);

}

uint8_t Key_GetNum()
{
    uint8_t KeyNum = 0;
    if(GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_1) == 0 )
    {
        Delay_ms(20);
        while(GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_1) == 0)
        Delay_ms(20);
        KeyNum = 1 ;        
    }
    if(GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_11) == 0 )
    {
        Delay_ms(20);
        while(GPIO_ReadInputDataBit(GPIOB , GPIO_Pin_11) == 0)
        Delay_ms(20);
        KeyNum = 2 ;        
    }
    return KeyNum;
}
  • AD
#ifndef __AD_H
#define __AD_H

void AD_Init(void);
uint16_t AD_GetLightH(void);
uint16_t AD_GetLightL(void);

#endif 
#ifndef __KEY_H
#define __KEY_H

void Key_Init(void);
uint8_t Key_GetNum(void);

#endif 
#include "stm32f10x.h"

#define Light_Pin GPIO_Pin_5 
#define Light_Channel ADC_Channel_5 
#define Light_High 3200
#define Light_Low 2000

void AD_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 , ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);

    RCC_ADCCLKConfig(RCC_PCLK2_Div6); //预分频 

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin = Light_Pin;
    GPIO_Init(GPIOA , &GPIO_InitStructure);

    ADC_RegularChannelConfig(ADC1 , Light_Channel , 1 , ADC_SampleTime_55Cycles5);

    ADC_InitTypeDef ADC_InitStructure;
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent ; //ADC独立模式
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right ;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;     
    //ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  //不连续转换
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;  // 连续转换
    ADC_InitStructure.ADC_NbrOfChannel = 1;  //连续转换通道数
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;  //扫描模式     
    ADC_Init(ADC1 , &ADC_InitStructure);

    ADC_Cmd(ADC1 , ENABLE);
    
    ADC_ResetCalibration(ADC1);
    while (ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while (ADC_GetCalibrationStatus(ADC1));
    
    ADC_AnalogWatchdogSingleChannelConfig(ADC1, Light_Channel);
    ADC_AnalogWatchdogThresholdsConfig(ADC1, Light_High, Light_Low);
    ADC_AnalogWatchdogCmd(ADC1, ADC_AnalogWatchdog_SingleRegEnable);

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

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

    ADC_ITConfig(ADC1 , ADC_IT_AWD , ENABLE);

    ADC_SoftwareStartConvCmd(ADC1,ENABLE); //连续转换时放这里

}

uint16_t AD_GetLightH(void)
{
    return Light_High;
}

uint16_t AD_GetLightL(void)
{
    return Light_Low;
}
  • Serial
#ifndef __SERIAL_H
#define __SERIAL_H
#include <stdio.h>

extern uint8_t RxData_Flag;

void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array , uint16_t Length);
void Serial_SendString(char *String);
uint32_t Serial_Pow(uint32_t x, uint32_t y);
void Serial_SendNumber(uint32_t Number , uint8_t Length);
void Serial_Printf(char *format , ...);
uint8_t Serial_GetRxFlag(void);
uint8_t Serial_GetRxData(void);

#endif 
#include "stm32f10x.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdio.h>
#include "LED.h"

uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
uint8_t RxData_Flag;

void Serial_Init()
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 ,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);
    

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_Init(GPIOA , &GPIO_InitStructure);
    GPIO_SetBits(GPIOA,GPIO_Pin_9);
     
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_Init(GPIOA , &GPIO_InitStructure);
    GPIO_SetBits(GPIOA,GPIO_Pin_10);

    USART_InitTypeDef  USART_InitSruture;
    USART_InitSruture.USART_BaudRate = 9600;
    USART_InitSruture.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 
    USART_InitSruture.USART_Mode =USART_Mode_Tx | USART_Mode_Rx ;      
    USART_InitSruture.USART_Parity =USART_Parity_No ; //odd 奇校验  even 偶校验
    USART_InitSruture.USART_StopBits =USART_StopBits_1 ;
    USART_InitSruture.USART_WordLength =USART_WordLength_8b ; 
    USART_Init(USART1 , &USART_InitSruture);

    USART_ITConfig(USART1 ,USART_IT_RXNE , ENABLE );

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

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

    USART_Cmd(USART1 , ENABLE);


}

void Serial_SendByte(uint8_t Byte)
{
    USART_SendData(USART1 , Byte);
    while (USART_GetFlagStatus(USART1 , USART_FLAG_TXE) == RESET);
    
}
void Serial_SendArray(uint8_t *Array , uint16_t Length)
{
    uint16_t i ;
    for ( i = 0; i < Length; i++)
    {
        Serial_SendByte(Array[i]);
    }

}

void Serial_SendString(char *String)
{
    uint8_t i;
    for(i = 0 ; String[i] != 0 ; i++)
    {
        Serial_SendByte(String[i]);
    }
}

uint32_t Serial_Pow(uint32_t x, uint32_t y)
{
    uint32_t Result =1 ;
    while (y--)
    {
        Result *= x;
    }
    return Result;
    
}

void Serial_SendNumber(uint32_t Number , uint8_t Length)
{
    uint8_t i ;
    for ( i = 0; i < Length; i++)
    {
        Serial_SendByte(Number / Serial_Pow(10 , Length - i - 1  ) % 10  + '0');
    }

    

}

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

void Serial_Printf(char *format , ...)
{
    char String[100];
    va_list arg;
    va_start(arg , format);
    vsprintf(String , format , arg);
    va_end(arg);
    Serial_SendString(String);
}

uint8_t Serial_GetRxFlag(void)
{
    if (Serial_RxFlag == 1)
    {
        Serial_RxFlag = 0 ;
        return 1;
    }
    return 0 ;
}

uint8_t Serial_GetRxData(void)
{
    return Serial_RxData ;
}



void USART1_IRQHandler(void)
    {
        if(USART_GetITStatus(USART1 , USART_IT_RXNE) == SET)
        {
        if (USART_ReceiveData(USART1) == 1)
		{
        	LED0_ON();
			RxData_Flag = 1;
		}
		else if (USART_ReceiveData(USART1) == 2)
		{
			LED0_OFF();
			RxData_Flag = 2;
		}
		else if (USART_ReceiveData(USART1) == 3)
		{
			RxData_Flag = 3;
		}

            USART_ClearITPendingBit(USART1 , USART_IT_RXNE);
        }
    }