双轴按键摇杆+STM32+51单片机+(小马达)直流电机

非专业,但对嵌入式微控制器以及01感到些许兴趣,特学习一番。

文章目录

目录

文章目录

前言

一、硬件接线

二、实现效果

三、步骤

1.两个软件分别写程序

2.51程序

3.STM32的程序:

4.源链接



前言

  1.  于51之后,最近学习STM32(stm32f103c8单片机最小系统板)。
  2. 写下这篇文章,记录学过的一些东西。
  3. 本章主要结合内容: 按键开关、双轴摇杆模块的ADC模数转换、输出PWM到51开发板步进电机模块控制小马达、STM32与51串口通信发送信息、OLED显示屏 ...
  4. 由于缺少电机驱动模块,恰好利用51开发板上的步进电机模块,同时实现串口通信就可以在51上的数码管或者LCD1602显示屏显示更多变量信息。

一、硬件接线

二、实现效果

  • 视频:  由于摇杆模块精度问题,模量变化太快,实验不太理想。

    STM32与51开发板电机驱动+PWM+串口通信

三、步骤

1.两个软件分别写程序

STM32使用的库函数编程,可以到B站找大佬视频学习和理解,在此不加以解释。明白这些存在,运用这些功能,乐哉乐哉。

  • Keil5 C51软件——51单片机
  • Keil5 MDK软件——STM32

2.51程序

  1. main.c :51开发板主要就接收来自STM32的串口数据(速度显示在1/2/3数码管)。而P1^0到P1^4已经与步进电机模块连接,直接在P1^0脚上输入PWM就可以了,这里电机的一端接01引脚,另一端接5V引脚(因为驱动能力问题电机一端必须要以5V供电,这就导致无法软件改变正反转,只有调速效果了),不过通过P1^6和P1^7两个引脚接正反转信号,在数码管上显示也足以判断。
    #include <REGX52.H>
    #include "Delay.h"
    #include "Nixie.h"
    #include "UART.H"
    
    sbit PWM=P1^0;
    sbit AIN1=P1^6;
    sbit AIN2=P1^7;
    
    unsigned char Information;
    
    void main()
    {
    	UART_INT1_Init();
    	while(1) 
    	{
    		Nixie(5,PWM);   //第五数码管:PWM输入变化显示
    		Nixie(7,AIN1);  //第七数码管:正反转判断1显示
    		Nixie(8,AIN2);  //第八数码管:正反转判断2显示
    
    		Nixie(1,Information/100);      //一:速度百位
    		Nixie(2,(Information%100)/10); //二:速度十位
    		Nixie(3,(Information%100)%10); //三:速度个位
    	}
    }
    
    /**
      *  @brief  串口中断服务程序(当STM32发送数据过来,INT1脚有高电平,"RI=0"且产生串口中断,51单片机开始接收数据读到(SBUF)接收缓冲寄存器)
      *  @param  无参数
      *  @retval 无返回值
      *  @danger 类型
    * */
    void UART_Routine() interrupt 4    //+串口中断号
    {
    	if(RI==1)   //如果接受完毕
    	{
    		Information = SBUF;
    		RI=0;      //必须清零
    	}
    }
    

  2. Uart.h :P3_0脚接收串口数据,P3^1脚串口发送。
#include <REGX52.H>

/**
  *  @brief  对串口初始化,串口传输“波特率”=4800bps,@12.00MHz
  *  @param  无输入参数
  *  @retval 无返回值
  *  @danger 单片机发送得和PC端接收到的数据不一样,最有可能是波特率设置的误差所造成
             UART通信传输的是HEX模式(即字符对应的ASC2码值)。
  */
void UART_INT1_Init(void)
{
	SCON = 0x50;   //(SCON)串行控制寄存器:0101 0000 ,
	               //(SM0=0,SM1=1:工作方式一,REN位=1:允许串行口接受数据)
	PCON |= 0x80;    //(PCON)波特率选择寄存器:1000 0000 , (使用串行通信方式1的波特率)波特率加倍
	
	TMOD &= 0x0F;   //(TMOD)定/计器工作模式寄存器:0000 xxxx,(该“与运算”不影响“定/计器0”的模式)
	                //把“定/计器1”用做定时模式工作,且只有INT1(P3.3)脚为高及TR1为1时才打开“定/计器1”
	TMOD |= 0x20;   //(TMOD)定/计器工作模式寄存器:0010 xxxx,(该“或运算”不影响“定/计器0”的状态),
	                //设置“定/计器1”为(定时)工作模式2,(M1=1,M0=0)8位自动重装载定时器,定时溢出时TH1的值自动重装入TL1里面。
	
	TL1 = 0xF4;    //设置了定时的初值
	TH1 = 0xF4;    //设置定时重装值,根据所需要的“波特率”计数
	
	ET1 = 0;     //禁止定时器T1中断
	TR1 = 1;     //定时器T1开始计时要素之一,另外还要等INT1脚为高电平
	
//------------串口接收时设置,允许串口中断且还要注意SCON串行寄存器得REN位也要置1,两个通信设备之间波特率设置没问题,就可以实现数据传输。
	EA = 1;
	ES = 1;
}

/**
  *  @brief  从INT1脚开始串口发送一个字节数据函数(将数据写到(SBUF)发送缓冲寄存器,共其他设备读取)
  *  @param  要发送的一个字节(8位)
  *  @retval 无返回值
  *  @danger 类型
  */
void UART_INT1_SendByte(unsigned char Byte)
{
	SBUF=Byte;      //_写数据(1字节=8个位)到(SBUF)缓存器
	while(TI==0) ;  //"TI"发送中断请求位表示检测是否发送完毕,(TI==1时)发送完退出循环
	TI=0;           //每次发送完一字节后,"TI"位必须软件清0,以准备重新装填发送 
}

/**
  *  @brief  发送一串字符数据函数(字符串循环将串分成单个字节放到SBUF寄存器)
  *  @param  要发送的字符串首地址
  *  @retval 无返回值
  *  @danger 地址参数
  */
void UART_INT1_SendString(unsigned char *str)
{
	while(*str != '\0')
		{
			UART_INT1_SendByte(*str);
			str++;
		}
}

3.STM32的程序:

  1. main.c :   获取双轴按键摇杆XY轴的AD信号,这里只用Y轴控制电机。用独立按键至状态开启,则在摇杆向y轴摇动杆时速度(Speed)大小与捕获到AD量的关系见程序。    调用Motor的函数传入速度值改变输出的PWM。       OLED显示屏:1行、显示X轴ADC量;2行、显示Y轴ADC量;3行、显示正/反转Speed值 与 开启/关闭。      最后,结果将Speed值修正通过串口发送给51单片机。

    #include "stm32f10x.h"                  // Device header
    #include "Delay.h"
    #include "OLED.h"
    #include "YGADC.h"
    #include "SERIAL.h"
    #include "Motor.h"
    #include "Key.h"
    
    uint16_t ADCXvalue ,ADCYvalue; //X,Y变量
    uint8_t KeyNum,on_of ;   //按键,开关变量
    int8_t Speed,SendSpeed;   //速度档,串口发送速度变量
    
    int main(void)
    {
    	OLED_Init();  //初始化OLED显示屏
    	ACD_Init();   //初始化摇杆模块ADC转换
    	Serial_Init();//初始化串口通信
    	Motor_Init(); //初始化电机驱动
    	Key_Init();   //初始化按键
    	
    //	Serial_SendString("Wellcome XY :\r\n");
    	OLED_ShowString(1,1,"ADCX:");
    	OLED_ShowString(2,1,"ADCY:");
    	
    	while(1)
    	{
    		ADCXvalue=ADC_Getvalue(ADC_Channel_0); //返回值是通道0
    		ADCYvalue=ADC_Getvalue(ADC_Channel_1); //返回值是通道1
    		
    		OLED_ShowNum(1,6,ADCXvalue,4); //OLED显示值
    		OLED_ShowNum(2,6,ADCYvalue,4);
    		
    		KeyNum = Key_GetNum();
    		if (KeyNum == 1)      //如果按键按下,开启/关闭电机运动
    		{
    			on_of++;
    			on_of %= 2;
    		}
    		if(on_of == 1)      //如果开启,将摇杆的模拟数字量分段,在每一段期间匹配一个决定电机速度的PWM
    		{
    			if(1900<=ADCYvalue && ADCYvalue<=2200)    //停止转动
    				Speed = 0;
    			else if(2200<ADCYvalue && ADCYvalue<=2560)  //正转
    				Speed = 20;
    			else if(2560<ADCYvalue && ADCYvalue<=2920)
    				Speed = 40;
    			else if(2920<ADCYvalue && ADCYvalue<=3280)
    				Speed = 60;
    			else if(3280<ADCYvalue && ADCYvalue<=3640)
    				Speed = 80;
    			else if(3640<ADCYvalue && ADCYvalue<=4100)
    				Speed = 100;
    			else if(1540<ADCYvalue && ADCYvalue<=1900)  //反转
    				Speed = -20;
    			else if(1180<ADCYvalue && ADCYvalue<=1540)
    				Speed = -40;
    			else if(820<ADCYvalue && ADCYvalue<=1180)
    				Speed = -60;
    			else if(160<ADCYvalue && ADCYvalue<=820)
    				Speed = -80;
    			else if(0<ADCYvalue && ADCYvalue<=160)
    				Speed = -100;
    		}
    		
    		Motor_SetSpeed(Speed);  //产生PWM输出
    		OLED_ShowSignedNum(3, 2, Speed, 3);
    		OLED_ShowNum(3, 10, on_of, 1);
    		
    		if(Speed > 0)  //if+else 保证串口发送速度参数为正数
    			{SendSpeed = Speed;}
    		else
    			{SendSpeed = -Speed;}
    		Serial_SendByte(SendSpeed);	  //串口发送
    		Delay_ms(100);  //延时时间,决定着采样摇杆数据,以及串口发送的频率
    	}
    }

  2. Motor.c :    电机速度(变量Speed)的正负值传入到CCR3,并由PA4和PA5脚( 推挽输出)决定正反转。

    /******	(电机驱动)
    *******PBA2总线 —— 开启时钟 GPIOA 
    *******输出脚:PA4 、PA5
    *******
    *******
    */
    
    #include "stm32f10x.h"                  // Device header
    #include "PWM.h"
    
    void Motor_Init(void)
    {
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	
    	PWM_Init();
    }
    
    void Motor_SetSpeed(int8_t Speed) //正反转与速度大小
    {
    	if (Speed >= 0)
    	{
    		GPIO_SetBits(GPIOA, GPIO_Pin_4);
    		GPIO_ResetBits(GPIOA, GPIO_Pin_5);
    		PWM_SetCompare3(Speed);
    	}
    	else
    	{
    		GPIO_ResetBits(GPIOA, GPIO_Pin_4);
    		GPIO_SetBits(GPIOA, GPIO_Pin_5);
    		PWM_SetCompare3(-Speed);
    	}
    }
  3. PWM.c  :    TIM2时钟通道3装载CCR3值,由PA2脚(复用推挽输出)产生PWM输出。

    /******	(PWM1输出)
    *******PBA2总线 —— 开启时钟 TIM2、GPIOA 
    *******输出脚:PA2
    *******
    *******
    */
    
    #include "stm32f10x.h"                  // Device header
    
    void PWM_Init(void)
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    	
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	
    	TIM_InternalClockConfig(TIM2);
    	
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    	TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;		//ARR
    	TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1;	//PSC
    	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
    	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
    	
    	TIM_OCInitTypeDef TIM_OCInitStructure;
    	TIM_OCStructInit(&TIM_OCInitStructure);
    	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    	TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
    	TIM_OC3Init(TIM2, &TIM_OCInitStructure);
    	
    	TIM_Cmd(TIM2, ENABLE);
    }
    
    void PWM_SetCompare3(uint16_t Compare)
    {
    	TIM_SetCompare3(TIM2, Compare);
    }
    
  4. YGADC.c :摇杆模块ADC捕获程序,通过PA0和PA1脚(模拟输入)获取XY轴的模拟信号。

    /******	(XYZ摇杆模块/模数转换1)
    *******PBA2总线 —— 开启时钟ADC1、GPIOA 
    ******* 输入脚:PA0 、PA1
    *******
    *******
    */
    
    #include "stm32f10x.h"                  // Device header
     
    void ACD_Init(void)
    {
    	//配置时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//开启ADC的时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启引脚GPIOA时钟
    	
    	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADC分频器六分频  72/6=12hz
    	//配置GPIOA
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
     
    	//配置ADC结构体
    	ADC_InitTypeDef ADC_Initstructure;
    	ADC_Initstructure.ADC_Mode=ADC_Mode_Independent;     //模式配置 独立模式
    	ADC_Initstructure.ADC_DataAlign=ADC_DataAlign_Right; //对其模式 右对齐
    	ADC_Initstructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None; //出发控制的触发源   不需要外部触发
    	ADC_Initstructure.ADC_ContinuousConvMode=DISABLE;    //连续模式 enable 连续   disable  单次
    	ADC_Initstructure.ADC_ScanConvMode=DISABLE;  //扫描模式 enable扫描模式   disable非扫描
    	ADC_Initstructure.ADC_NbrOfChannel=1;      //指定规则组通道的数目
     
    	ADC_Init(ADC1,&ADC_Initstructure);
     
    	ADC_Cmd(ADC1,ENABLE); //ADC上电
    	 
    	//校准
    	ADC_ResetCalibration(ADC1);//复位校准
    	while(ADC_GetResetCalibrationStatus(ADC1)==SET);//返回复位校准的状态  如果没完成就一直循环 复位后会清零
    	ADC_StartCalibration(ADC1);//开始校准
    	while(ADC_GetCalibrationStatus(ADC1)==SET);//校准是否完成,如果没完成就一直循环
    	 
    }
    
    
    uint16_t ADC_Getvalue(uint8_t ADC_Channel) //输入通道获取值
    {
    		//ADC通道配置  、输入通道可以获取值
    	ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5);//在序列1写入通道0  时间55.5个ADC时间
    	
    	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发转换
    	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);//获取标志位状态  规则组转换完成标志位   0转换未完成  1	转换完成
    	return ADC_GetConversionValue(ADC1);
    }
    
  5. Key.c:按键开关,PB1脚(上拉输入)得到开关信号吧。

    /******	(按键)
    *******PBA2总线 —— 开启时钟 GPIOB 
    ******* 输入脚:PB1
    *******
    *******
    */
    
    #include "stm32f10x.h"                  // Device header
    #include "Delay.h"
    
    /*****************************************************
    *********函数:初始化PB1按键的读取端口**********
    *********返回值:无
    ******************************************************/
    void Key_Init(void)
    {
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    	
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	
    	GPIO_Init(GPIOB,&GPIO_InitStructure);
    }
    
    /************************************************
    ***************函数:获取按键的状态********************
    ***************返回值:相应按键变化(按下PB1返回:1 )
    ************************************************/
    uint8_t Key_GetNum(void)
    {
    	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;
    	}
    	return KeyNum;
    }
    
    

  6. Serials.c :串口通信(可发送可接收)。PA9脚发送(复用推挽输出)PA10接收数据(上拉输入)

    /******	(串口通信1)
    *******PBA2总线 —— 开启时钟USART1、GPIOA 
    *******输出脚Tx:PA9   读入脚Rx:PA10
    *******
    *******
    */
    
    #include "stm32f10x.h"  // Device header
    #include <stdio.h>   //printf()
    #include <stdarg.h>  //sprintf()
    
    /****为串口中断产出的变量*****/
    uint8_t serial_RxData;
    uint8_t serial_RxFlag;
    
    void Serial_Init(void)
    {
    	//开启时钟:打开USART(1/2)和GPIOx(A/B/C)
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);  //开启USART1的时钟(总线APB2上)
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   //开启GPIOA的时钟(TX1与RX1分在PA9与PA10脚)
    	
    	//GPIO初始化: TX配置复用输出,RX配置输入
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //对于TX脚是外设输出脚所以配复用推挽输出。RX脚是外设数据输入脚所以配输入模式
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;  //TX脚
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //对于RX脚是外设输入脚(IPD浮空输入或者IPU上拉输入)。
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;  //RX脚
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	
    	//配置USART: 一个结构体包含所需参数。
    	USART_InitTypeDef USART_InitStructure;
    	USART_InitStructure.USART_BaudRate = 4800;  //波特率
    	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  //硬件流控制(不使用、只用CTS、只用RTS或者CTS、RST都用)
    	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //模式:发送功能_TX 或 接收功能_RX
    	USART_InitStructure.USART_Parity = USART_Parity_No;  //校验位(No无校验、Odd奇校验、Even偶校验)
    	USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位(1、1.5、2)
    	USART_InitStructure.USART_WordLength = USART_WordLength_8b;  //字长:(8位/9位)
    	USART_Init(USART1, &USART_InitStructure);
    	//使能命令以后就可以直接(发送)和(查询接收)。(接收两种:1、主函数不断查询判断RXNE标志位;2、需另设中断)。
    	
    	//接收:中断方式
    	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //RXNE标志位、使能
    	/******RXNE置1,串口可以开始申请中断************/
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    	NVIC_InitTypeDef NVIC_InitStrruct;    
    	NVIC_InitStrruct.NVIC_IRQChannel = USART1_IRQn;        //中断通道
    	NVIC_InitStrruct.NVIC_IRQChannelCmd = ENABLE;          //使能
    	NVIC_InitStrruct.NVIC_IRQChannelPreemptionPriority = 1; //优先级
    	NVIC_InitStrruct.NVIC_IRQChannelSubPriority = 1;        // ···
    	NVIC_Init(&NVIC_InitStrruct);
    	
    	USART_Cmd(USART1, ENABLE);
    }
    
    
    //发送一个字节(8位)
    void Serial_SendByte(uint8_t Byte)
    {
    	USART_SendData(USART1, Byte);  //传送数据,写到TDR >>转移到移位寄存器
    	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);  //等待 TXE标志位置1(下次会自动清零) 
    }
    
    //发送数组(首地址、长度(16位或者32位))
    void Serial_SendArray(uint8_t *Array, uint16_t Length)
    {
    	uint16_t i;
    	for (i = 0; i < Length; i ++)
    	{
    		Serial_SendByte(Array[i]); //依次发送数组的每一项
    	}
    }
    
    //发送字符串(char类型字符串首地址)
    void Serial_SendString(char *String)
    {
    	uint8_t i;
    	for (i = 0; String[i] != '\0'; i ++)
    	{
    		Serial_SendByte(String[i]);
    	}
    }
    
    //数字取余运算(10、次数)
    //返回值:余数
    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'); //传送取余数
    	}
    }
    
    //printf()打印函数的原型(单串口)
    //调用形式:printf("%d",变量);
    int fputc(int ch, FILE *f)
    {
    	Serial_SendByte(ch); //重印象到TX脚输出
    	return ch;
    }
    
    //一次多个参数输出
    //(格式化字符串、可变量参数x表)
    void Serial_Printf(char *format, ...)
    {
    	char String[100];
    	va_list arg;                   //定义参数列表变量
    	va_start(arg, format);         //从format接收放在arg里
    	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就退出
    	}
    	return 0;
    }
    
    //封装变量
    uint8_t Serial_GetRxData(void)
    {
    	return serial_RxData ;
    }
    
    //串口中断服务函数
    void USART1_IRQHandler(void)
    {
    	if(USART_GetFlagStatus(USART1,USART_IT_RXNE) == SET)
    	{
    		serial_RxData = USART_ReceiveData(USART1);
    		serial_RxFlag = 1;
    		USART_ClearITPendingBit(USART1,USART_IT_RXNE);
    	}
    }
    
  7. OLED.h:OLED显示屏得相关函数。

    #ifndef __OLED_H
    #define __OLED_H
    
    void OLED_Init(void);    //初始化OLED
    void OLED_Clear(void);   //清屏
    void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);      //显示一个字符
    void OLED_ShowString(uint8_t Line, uint8_t Column, char *String); //显示字符串
    void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);      //显示数字
    void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length); //显示带符号数字
    void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);   //显示十六进制数
    void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);   //显示二进制数
    
    #endif
    

4.源链接

51源程序与32源程序

链接:https://pan.baidu.com/s/1UIiPXW8kY37truW2c5Sbeg?pwd=3251 
提取码:3251


因兴趣而学习,简单了解电子世界。虽不是大项目,通过独立小小实验还是明白嵌入式微控器的运作原理。

拿上STM32引脚定义表与参考手册,方可琢透一二。

链接:https://pan.baidu.com/s/1i1oX7ntdjK0oj9A8VgoazQ?pwd=3251 
提取码:3251

  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值