STM32学习笔记05

前言

编程语言、硬件电路、软件编程、蜂鸣器驱动程序、MIDI音乐播放程序


目录

一、单片机编程语言

二、核心板电路原理图​编辑

三、 点亮LED灯

         ​GPIO库函数 

GPIO_WriteBit

GPIO_ResetBits

GPIO_SetBits

GPIO_Write

 三种方法

四、延时函数 

五、LED呼吸灯  

六、按键控制LED灯

七、Flash读写程序

Flash库函数 

FLASH操作注意事项


一、单片机编程语言

 二、核心板电路原理图

  • C6、C7晶振的起振电容
  • 继电器作为整个电源的电器开关
  • 用户通过PB0、PB1操纵灯的开关

  • FT232串口将USB接口转为TTL电平USART串口来给单片机ISP下载,也可以与电脑开发
  • 3.3V稳压芯片将USB电源中5V电压转为3.3V,来给单片机以及周边使用3.3V的器件供电
  • ASP控制芯片实现核心板程序自动下载
  • C9、R7组成单片机外部的复位电路
  • RTC备用电池是用来RTC不间断走时使用

三、 点亮LED灯

 对IO端口初始化,程序控制IO端口电平变化

PB0输出高电平,LED点亮;低电平,LED熄灭 

选择IO接口工作方式:

  • GPIO_Mode_AIN 模拟输入
  • GPIO_Mode_IN_FLOATING 浮空输入
  • GPIO_Mode_IPD 下拉输入
  • GPIO_Mode_IPU 上拉输入
  • GPIO_Mode_Out_PP 推挽输出
  • GPIO_Mode_Out_OD 开漏输出
  • GPIO_Mode_AF_PP 复用推挽输出
  • GPIO_Mode_AF_OD 复用开漏输出 

设置IO接口速度:(2/10/50MHz) 

推挽、上下拉、灌电流​​​​​​​

GPIO库函数 

GPIO_WriteBit

GPIO_ResetBits

清除端口位,低电平

GPIO_SetBits

置位端口位,高电平

GPIO_Write

给相应的端口写值

 三种方法

#include "stm32f10x.h" //STM32头文件
#include "sys.h"
#include "delay.h"
#include "led.h"

int main (void){//主程序
	RCC_Configuration(); //时钟设置
	LED_Init();  //端口初始化
	while(1){
		
		//方法一
		GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1)); //LED1接口输出高电平,BitAction是枚举值
		delay_s(1); //延时1秒
		GPIO_WriteBit(LEDPORT,LED1,(BitAction)(0));
		delay_s(1); //延时1秒

		//方法二
		GPIO_SetBits(LEDPORT,LED1);	  //置位端口位,为高电平
		delay_s(1); //延时1秒
		GPIO_ResetBits(LEDPORT,LED1);  //清除端口位,为低电平
		delay_s(1);

		//方法三
		GPIO_Write(LEDPORT,0x0001); //写入变量值
		delay_s(1); //延时1秒
		GPIO_Write(LEDPORT,0x0000); 
		delay_s(1);
	}
}

LED端口初始化

#include "led.h"

void LED_Init(void){ //LED灯的接口初始化
	GPIO_InitTypeDef  GPIO_InitStructure; 	
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);   //时钟上,启动APB2这条总线上功能    
    GPIO_InitStructure.GPIO_Pin =  LED1 | LED2; //选择端口号(0~15或all)                        
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择IO接口工作方式       
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz)    
	GPIO_Init(LEDPORT, &GPIO_InitStructure);			
}

四、延时函数 

用到滴答定时器

#include "delay.h"


#define AHB_INPUT  72  //RCC中设置的AHB时钟频率填写到这里(单位MHz)


void delay_us(u32 uS){ //uS微秒级延时程序(参考值即是延时数,72MHz时最大值233015)	
	SysTick->LOAD=AHB_INPUT*uS;      //重装计数初值(当主频是72MHz,72次为1微秒)
	SysTick->VAL=0x00;        //清空定时器的计数器
	SysTick->CTRL=0x00000005;//时钟源HCLK,打开定时器
	while(!(SysTick->CTRL&0x00010000)); //等待计数到0
	SysTick->CTRL=0x00000004;//关闭定时器
}

void delay_ms(u16 ms){ //mS毫秒级延时程序(参考值即是延时数,最大值65535)	 		  	  
	while( ms-- != 0){
		delay_us(1000);	//调用1000微秒的延时
	}
}
 
void delay_s(u16 s){ //S秒级延时程序(参考值即是延时数,最大值65535)	 		  	  
	while( s-- != 0){
		delay_ms(1000);	//调用1000毫秒的延时
	}
} 

五、LED呼吸灯  

 其实就是调节占空比,即点亮时间和熄灭时间的比例,点亮时间越长,亮度越大

#include "stm32f10x.h" //STM32头文件
#include "sys.h"
#include "delay.h"
#include "led.h"

int main (void){//主程序

    u8 menu;   //标记变暗还是变亮模式,定义8位无符号变量a
    u16 t,i;   //定义16位无符号变量a

    RCC_Configuration(); //时钟设置
    LED_Init();

    //初始化变量
    menu = 0;
    t = 1;      //延时值

    while(1){
        //呼吸灯
        //变亮
        if(menu == 0){
            //同一个亮度增加了十倍
            for(i = 1;i <= 10;i++){
                GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1)); //LED1接口输出高电平,BitAction是枚举值
                delay_us(t); //延时1微秒
                GPIO_WriteBit(LEDPORT,LED1,(BitAction)(0));
                delay_us(501-t); //延时1秒
            }
            t++;
            if(t == 500){
                menu = 1; //切换成变暗模式
            }
        }
        if(menu == 1){
            for(i = 1;i <=10;i++){
                GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1)); //LED1接口输出高电平,BitAction是枚举值
                delay_us(t); //延时1微秒
                GPIO_WriteBit(LEDPORT,LED1,(BitAction)(0));
                delay_us(501-t); //延时1秒
            }
            t--;
            if(t==1){
                menu = 0; //切换成变暗模式
            }
        }
    }
}

六、按键控制LED灯

  即读出按下按键后,此端口的值,根据这个值给灯的端口相应的电平

按键端口设为上拉电阻

#include "key.h"

void KEY_Init(void){ //微动开关的接口初始化
	GPIO_InitTypeDef  GPIO_InitStructure; //定义GPIO的初始化枚举结构	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);       
    GPIO_InitStructure.GPIO_Pin = KEY1; //选择端口号(0~15或all)                        
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //选择IO接口工作方式 //上拉电阻       
//    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz)    
	GPIO_Init(KEYPORT,&GPIO_InitStructure);			
}
#include "sys.h"

#define KEYPORT	GPIOA	//定义IO接口组
#define KEY1	GPIO_Pin_0	//定义IO接口


void KEY_Init(void);//初始化

 补充:按键在按下的瞬间会有电平的抖动,若按下就读,电平可能有高有低,所以要加一个延时

#include "stm32f10x.h" //STM32头文件
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "key.h"

int main (void){//主程序

	u8 a;

	RCC_Configuration(); //时钟设置
	LED_Init();
	KEY_Init();

	a = 0;
	

	while(1){

		 //按键控制LED
		 方法一,无锁存,没有按下按键该按键端口为高电平,按下为低电平
		if(GPIO_ReadInputDataBit(KEYPORT,KEY1)){
			GPIO_WriteBit(LEDPORT,LED1,(BitAction)(0));	//给LED端口低电平
		}
		else{
		 	GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1));	 //高电平
		}

		//方法二,无锁存
		GPIO_WriteBit(LEDPORT,LED1,(BitAction)(!GPIO_ReadInputDataBit(KEYPORT,KEY1)));

		//方法三,有锁存,按键按下才执行
		if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){
			delay_ms(20); //延时去抖动
			if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){
				GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1-GPIO_ReadOutputDataBit(LEDPORT,LED1)));	//根据LED端口值取反
				while(!GPIO_ReadInputDataBit(KEYPORT,KEY1)); //等待按键松开,按键放开才跳出	,防止在一直按下的情况,前面程序反复运行
			}
		}

		//方法四,有锁存
		if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){
			delay_ms(20); //延时去抖动
			if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){
				//两个LED显示2进制加法
				a++;
				if(a>3){
					a=0;
				}
				GPIO_Write(LEDPORT,a);	//直接数值操作将变量值写入LED(LED在GPIOB组的PB0和PB1上)
				while(!GPIO_ReadInputDataBit(KEYPORT,KEY1)); //等待按键松开
			}
		}

	}
}

七、Flash读写程序

在上面点亮LED灯时,当断电后再次打开,LED熄灭,如果有了Flash读写功能,就可以再次打开后,LED仍亮起来

Flash库函数 

#include "flash.h"

//FLASH写入数据
void FLASH_W(u32 add,u16 dat){ //参数1:32位FLASH地址。参数2:16位数据
//	 RCC_HSICmd(ENABLE); //打开HSI时钟   这里已经使用外部时钟,无需内部时钟
	 FLASH_Unlock();  //解锁FLASH编程擦除控制器
     FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);//清除标志位
     FLASH_ErasePage(add);     //擦除指定地址页,必须以页先擦除才可以写
     FLASH_ProgramHalfWord(add,dat); //从指定页的addr地址开始写
     FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);//清除标志位
     FLASH_Lock();    //锁定FLASH编程擦除控制器
}

//FLASH读出数据
u16 FLASH_R(u32 add){ //参数1:32位读出FLASH地址。返回值:16位数据
	u16 a;
    a = *(u16*)(add);//从指定页的addr地址开始读
return a;
}

地址

#include "stm32f10x.h" //STM32头文件
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "key.h"

#include "flash.h" 

#define FLASH_START_ADDR  0x0801f000	  //写入的起始地址

int main (void){//主程序

	u16 a;

	RCC_Configuration(); //时钟设置
	LED_Init();
	KEY_Init();


	a = FLASH_R(FLASH_START_ADDR);//从指定页的地址读FLASH

	GPIO_Write(LEDPORT,a); //直接数值操作将变量值写入LED(LED在GPIOB组的PB0和PB1上)
	


	while(1){

		//flash读写程序
		if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){
			delay_ms(20); //延时去抖动
			if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){
				//两个LED显示2进制加法
				a++;
				if(a>3){
					a=0;
				}
				GPIO_Write(LEDPORT,a);	//直接数值操作将变量值写入LED(LED在GPIOB组的PB0和PB1上)

				FLASH_W(FLASH_START_ADDR,a); //从指定页的地址写入FLASH

				while(!GPIO_ReadInputDataBit(KEYPORT,KEY1)); //等待按键松开
			}
		}
	}
}

注意:保持的临时数据要避免用户程序的地址,所以尽量选靠后地址

写入多个数据

 FLASH操作注意事项

  • 操作一定要先擦后写。
  • 每页是1024个地址,起始地址0x08000000。
  • 擦除操作以页为单位,写操作则必须以16位宽度为单位,允许跨页写入。
  • STM32内置FLASH擦或写时,必须打开外部/内部高速振荡器
  • FLASH可多次擦写10万次,不可死循环擦写。
  • 擦写时要避开用户程序存储区的区域,否则会擦掉用户程序导致错误。
  • 擦除一页要10ms(对于1k大小的一页),比较慢。而且不能单个字节的擦写。

八、蜂鸣器驱动程序

有源&无源蜂鸣器

外观几乎无区别,要通过型号辨别。

蜂鸣器部分电路图

 

PB5输入高电平,三极管C端和E端断开,BP1蜂鸣器断开。输入低电平,导通。但PB5不能长时间低电平,会导致蜂鸣器线圈长时间通电发热,导致损坏。所以需要保证PB5一般保持在高电平,因此加了一个上拉电阻。

 

频率周期的数量决定了蜂鸣器发声长度,每一个周期,高低电平占用时间,决定了蜂鸣器音调。频率越短声调越高。

#include "buzzer.h"
#include "delay.h"

void BUZZER_Init(void){ //蜂鸣器的接口初始化
	GPIO_InitTypeDef  GPIO_InitStructure; 	
    GPIO_InitStructure.GPIO_Pin = BUZZER; //选择端口号                        
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择IO接口工作方式       
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz)    
	GPIO_Init(BUZZERPORT, &GPIO_InitStructure);	
	
	GPIO_WriteBit(BUZZERPORT,BUZZER,(BitAction)(1)); //蜂鸣器接口输出高电平1		
}

void BUZZER_BEEP1(void){ //蜂鸣器响一声
	u16 i;
	for(i=0;i<200;i++){
		GPIO_WriteBit(BUZZERPORT,BUZZER,(BitAction)(0)); //蜂鸣器接口输出0
		delay_us(500); //延时		
		GPIO_WriteBit(BUZZERPORT,BUZZER,(BitAction)(1)); //蜂鸣器接口输出高电平1
		delay_us(500); //延时		
	}
}
#ifndef __BUZZER_H
#define __BUZZER_H	 
#include "sys.h"

#define BUZZERPORT	GPIOB	//定义IO接口
#define BUZZER	GPIO_Pin_5	//定义IO接口



void BUZZER_Init(void);//初始化
void BUZZER_BEEP1(void);//响一声

		 				    
#endif
#include "stm32f10x.h" //STM32头文件
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "buzzer.h"

#include "flash.h" 

#define FLASH_START_ADDR  0x0801f000	  //写入的起始地址

int main (void){//主程序

	u16 a;

	RCC_Configuration(); //时钟设置
	LED_Init();
	KEY_Init();

	BUZZER_Init();
	BUZZER_BEEP1();//蜂鸣器音1

	a = FLASH_R(FLASH_START_ADDR);//从指定页的地址读FLASH

	GPIO_Write(LEDPORT,a|0xfffc&GPIO_ReadOutputData(LEDPORT)); //直接数值操作将变量值写入LED(LED在GPIOB组的PB0和PB1上)
	

	while(1){

		//蜂鸣器驱动程序
		if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){
			delay_ms(20); //延时去抖动
			if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){
				//两个LED显示2进制加法
				a++;
				if(a>3){
					a=0;
				}
				GPIO_Write(LEDPORT,a|0xfffc&GPIO_ReadOutputData(LEDPORT));	//直接数值操作将变量值写入LED(LED在GPIOB组的PB0和PB1上)
			    BUZZER_BEEP1();//蜂鸣器音1

				FLASH_W(FLASH_START_ADDR,a); //从指定页的地址写入FLASH

				while(!GPIO_ReadInputDataBit(KEYPORT,KEY1)); //等待按键松开
			}
		}
	}
}



 注意这里一定是高电平为结束,防止蜂鸣器一直处于低电平状态。

 这里得注意,因为蜂鸣器所连端口是PB组的,其中LEDPORT=GPIOB,GPIO_Write(LEDPORT,a)将除了两个灯的端口全部设为0,GPIO_ReadOutputData(LEDPORT)为读取整租IO端口电平状态。0xfffc&GPIO_ReadOutputData(LEDPORT)按位与是高14位保持原来的状态,最低两位清零,再与a按位或,则电平由a的最低两位给出

九、MIDI音乐播放程序

 

uc16 music1[78]={ //音乐1的数据表(奇数是音调,偶数是长度),无符号只读变量
330,750,
440,375,
494,375,
523,750,
587,375,
659,375,
587,750,
494,375,
392,375,
440,1500,
330,750,
440,375,
494,375,
523,750,
587,375,
659,375,
587,750,
494,375,
392,375,
784,1500,
659,750,
698,375,
784,375,
880,750,
784,375,
698,375,
659,750,
587,750,
659,750,
523,375,
494,375,
440,750,
440,375,
494,375,
523,750,
523,750,
494,750,
392,750,
440,3000
};

void MIDI_PLAY(void){ //MIDI音乐
	u16 i,e;
	for(i=0;i<39;i++){	//有39个音符
		for(e=0;e<music1[i*2]*music1[i*2+1]/1000;e++){		//每个音符播放时间长度
			GPIO_WriteBit(BUZZERPORT,BUZZER,(BitAction)(0)); //蜂鸣器接口输出0
			delay_us(500000/music1[i*2]); //延时		
			GPIO_WriteBit(BUZZERPORT,BUZZER,(BitAction)(1)); //蜂鸣器接口输出高电平1
			delay_us(500000/music1[i*2]); //延时	
		}	
	}
}

音调为赫兹,长度为毫秒

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纯合子tt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值