蓝桥杯嵌入式(STM32F103RBT6)备赛手册(一)

2023-05-16

文章目录

  • 一.基础篇
    • 一.点亮LED
    • 二.驱动蜂鸣器
    • 三.Systick定时器
    • 四.定时器
    • 五.独立按键——三行代码消抖
    • 六.IIC协议
    • 七.LCD显示
    • 八.串口接收与发送
    • 九.ADC采样
    • 十.RTC时钟
    • 十一.PWM输出及输入捕获

一.基础篇

一.点亮LED

在这里插入图片描述

由原理图可以知道PC8-PC15控制LED灯,要通过设置GPIO来点亮灯,首先定义初始化结构体,然后使能对应的时钟(可以在rcc.c/.h文件中寻找相关的时钟函数),之后配置结构体(可以在gpio.h文件中查看每个变量可以填入的值),因为GPIO直接输出控制LED,不存在时钟复用,所以采用推挽输出,然后初始化结构体通过GPIO_SetBits(),GPIO_ResetBits()来控制寄存器置位清零来控制LED亮灭。
注意:要找什么外设的相关函数,就去什么模块对应的c/h文件去找,h文件有函数申明,以及函数的可选参数,c文件有函数的注释,用法等。

#include "stm32f10x.h"
#include "lcd.h"
#include "stm32f10x_gpio.h"

u32 TimingDelay = 0;

void LED_Init(void)
{
	
    GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD,ENABLE);//配置之前先开时钟

	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15|GPIO_Pin_All;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_Init(GPIOC,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;
	GPIO_Init(GPIOD,&GPIO_InitStructure);//配置LED_NLE才能往里写数据	
}
void LED_Control(u16 led_ctrl)
{
	GPIO_SetBits(GPIOC,GPIO_Pin_All);//LED为低电平点亮,先将所有LED关闭
	GPIO_ResetBits(GPIOC,led_ctrl<<8); //低电平点亮
    GPIO_SetBits(GPIOD,GPIO_Pin_2);//开启锁存器可以往里写数据
    GPIO_ResetBits(GPIOD,GPIO_Pin_2);//写完数据以后关闭锁存器
}
void Delay_Ms(u32 nTime);
//Main Body
int main(void)
{
	
	LED_Init();
	//刚开始初始化好结构体,全为低电平
	LED_Control(0xff);
	while(1);
}
void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

二.驱动蜂鸣器

为了优化外设数目,可以把一些复用功能映射到其他引脚上;比如:LSE 振荡器关闭时, LSE 振荡器引脚 OSC32_IN/OSC32_OUT 可以分别用做 GPIO 的 PC14/PC15,LSE功能始终优先于通用I/O口的功能,此为端口重映射

在这里插入图片描述
在这里插入图片描述

对于CT117E的蜂鸣器,控制他的引脚为N Buzz对应GPIO为PB4,PB4的重映射为JNTRST功能,现在只想用PB4用作一般GPIO口,不需要JNTRST功能,可以通过控制SWJ_CFG[2:0]位来改变重映射,而改变重映射不能取消SWJ功能,SWJ在下载程序和仿真时使用,只取消JNTRST,所以设置SWJ_CFG[2:0]为001,使用函数GPIO_PinRemapConfig()设置重映射来关闭JNTRST
注意写配置函数时候先打开时钟以后再配置重映射等其他东西对于蜂鸣器电路图,蜂鸣器引脚给0低电平则触发蜂鸣器,给1高电平则关闭蜂鸣器

为了在调试期间可以使用更多GPIOs,通过设置复用重映射和调试I/O配置寄存器(AFIO_MAPR) 的SWJ_CFG[2:0]位,可以改变上述重映像配置。参见下表。

在这里插入图片描述

buzzer.c
#include "buzzer.h"
void Buzzer_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);
	//改变引脚映射
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
}
buzzer.h
#ifndef __BUZZER_H
#define __BUZZER_H
#include "stm32f10x.h"
#define Buzzer_ON    GPIO_ResetBits(GPIOB,GPIO_Pin_4)
#define Buzzer_OFF   GPIO_SetBits(GPIOB,GPIO_Pin_4)
void Buzzer_Init(void);

#endif
main.c
#include "stm32f10x.h"
#include "lcd.h"
#include "buzzer.h"

u32 TimingDelay = 0;

void Delay_Ms(u32 nTime);

//Main Body
int main(void)
{
	SysTick_Config(SystemCoreClock/1000);

	Delay_Ms(200);
	
	Buzzer_Init();
	Buzzer_ON;
	while(1);
}

//
void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

三.Systick定时器

通过SysTick_Config(SystemCoreClock/1000);此函数配置SysTick定时器,其中参数为配置重装载计数器的值,用此函数打开计数器之后,函数参数开始减少,每当参数减小到0时即开始一次中断,执行中断然后参数又恢复到原来的值继续递减。 而SystemCoreClock为72 000 000即1s震动72 000 000次,SystemCoreClock除以1000即1ms震动72 000次,从72 000开始递减每次执行这个函数可以减1,减72 000次的时间是1ms,即每产生一次中断的时间是1ms,所以可以让中断事件为一个数值递减的函数,即每次产生中断这个数递减1,那么可以实现定时器延时。

在这里插入图片描述
在这里插入图片描述

除此之外,还要在stm32f10x_it.c中找到对应的中断函数名,在这个函数里填入中断事件
在这里插入图片描述
即通过SysTick_Config设置了震动每1ms中断一次,对应的中断函数名是SysTick_Handler中断事件是TimingDelay减1,通过赋予nTime的值赋予TimingDelay实现延时

led.c
#include "led.h"
void Led_Init()
{
    GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15|GPIO_Pin_All;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_Init(GPIOC,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;
	GPIO_Init(GPIOD,&GPIO_InitStructure);
}
void Led_Control(u16 led_ctrl,u16 index)
{
    GPIO_SetBits(GPIOC,GPIO_Pin_All);
    GPIO_ResetBits(GPIOC,led_ctrl<<(8+index));	
    GPIO_ResetBits(GPIOD,GPIO_Pin_2);
	GPIO_SetBits(GPIOD,GPIO_Pin_2);
}
led.h
#ifndef __LED_H
#define __LED_H
#include "stm32f10x.h"
void Led_Init();
void Led_Control(u16 led_ctrl,u16 index);

#endif
main.c
#include "stm32f10x.h"
#include "lcd.h"
#include "buzzer.h"
#include "led.h"
#include "timer.h"
u32 TimingDelay = 0;

_Bool Buzzer_Flag=0;

void Delay_Ms(u32 nTime);

//Main Body
int main(void)
{
	u16 index;
	SysTick_Config(SystemCoreClock/1000);

	Delay_Ms(200);
	Led_Init();
	Buzzer_Init();
	while(1)
	{
		Buzzer_OFF;
	    for(index=0;index<8;index++)
		{
		    Led_Control(0x01,index);
			Delay_Ms(500);
		}
		Buzzer_ON;
		Delay_Ms(500);
		
	}
}

//
void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

四.定时器

中断定时器:有基本定时器,通用定时器,高级定时器,TIM1到TIM8,TIM1和TIM8是高级定时器,TIM6和TIM7是基本定时器,其余的是通用定时器使用外部定时器需要和中断向量控制器NVIC配合使用。
使用前先新建一个c文件,用来存放定时器TIM的配置和中断向量控制器NVIC的配置,先配置定时器的结构体。

在这里插入图片描述

其中TIM_Prescaler为预分频系数,可以从0到71之间配置,0为不分频或者1分频,都是它本身, 71则是72分频,原来时钟频率为72 000 000,即72MHz,72分频后为1 000 000,即1Mhz,也就是1us。
其中TIM_Period为计数周期,从0开始计数,设置为999,即1000个1us,即1ms;
其中TIM_CounterMode为计数模式,向上计数则为0,1,2,3…999,向下计数则为1000,999…1
其中TIM_ClockDivision也是分频系数,一般配置为0
其中TIM_RepetitionCounter通用定时器没有此功能 然后配置好结构体后调用Init函数初始化结构体,然后TIM_ITConfig()来开启中断,最后使用TIM_Cmd()来打开定时器

NVIC配置:NVIC的函数存放在misc.h中,在配置好结构体之前要先NVIC_PriorityGroupConfig()通过此函数配置中断向量优先级分组,之后配置好结构体

在这里插入图片描述

其中NVIC_IRQChannel来设置中断源,中断源名字从stm32f10x.h中寻找
其中NVIC_IRQChannelPreemptionPriority为主优先级其中NVIC_IRQChannelSubPriority为次优先级
其中NVIC_IRQChannelCmd为中断使能,ENABLE和DISABLE
主优先级和次优先级的设置都要和中断向量优先级分组相匹配,然后将NVIC的配置整体放于TIM配置前,数字越小优先级越高
最后写入中断函数,中断函数可以写在stm32f10x_it.c中,也可以写在main.c文件中,中断函数名不可以随便起,要在启动文件中查找,中断函数中要通过TIM_GetITStatus()函数检查是否中断函数标志位置位,即if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET),然后通过TIM_ClearITPendingBit(TIM2,TIM_IT_Update)清除标志位,在清除标志位的同时写入中断函数内容。外部中断的好处是可以在CPU执行别的语句时同时计时产生中断,不浪费时间,SysTick则浪费时间

timer.c
#include "time.h"
#include "stm32f10x_tim.h"
void NVIC_Config(void);
void TIM2_Init(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	NVIC_Config();
	//设置预分频系数,从0开始计数,0是不分频,即1分频,71则是72分频
	TIM_TimeBaseInitStructure.TIM_Prescaler=71;//原来为72 000 000,72分频之后得1 000 000即1Mhz,也就是1us
	//设置计数模式
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	//设置计数周期
	TIM_TimeBaseInitStructure.TIM_Period=1000-1;//也是从0开始计数所以从0记到999,即1000个1us,1ms
	//也是分频系数,没多大用,一般设置为0
	TIM_TimeBaseInitStructure.TIM_ClockDivision=0;
	//配置重复计算器,通用定时器没有此功能
	//配置好定时器
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	//开启中断
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	//开启定时器
	TIM_Cmd(TIM2, ENABLE);
}
void NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	
	NVIC_Init(&NVIC_InitStructure);
}
timer.h
#ifndef __TIMER_H
#define __TIMER_H
#include "stm32f10x_tim.h"
void TIM2_Init(void);
void NVIC_Config(void);
#endif

#include "stm32f10x.h"
#include "lcd.h"
#include "buzzer.h"
#include "led.h"
#include "timer.h"
u32 TimingDelay = 0;

_Bool Buzzer_Flag=0;

void Delay_Ms(u32 nTime);

//Main Body
int main(void)
{
	u16 index;
	SysTick_Config(SystemCoreClock/1000);

	Delay_Ms(200);
	Led_Init();
	Buzzer_Init();
	TIM2_Init();
	while(1)
	{
//		Buzzer_OFF;
//	    for(index=0;index<8;index++)
//		{
//		    Led_Control(0x01,index);
//			Delay_Ms(500);
//		}
//		Buzzer_ON;
//		Delay_Ms(500);
		if(Buzzer_Flag==1)
		{
		    Buzzer_ON;
		}
		else
		{
		    Buzzer_OFF;
		}
	}
}

//
void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}
void TIM2_IRQHandler(void)
{
	static u16 Buzzer_Count=0;
    if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)
	{
	    TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
		Buzzer_Count++;
		if(Buzzer_Count==500)
		{
		    Buzzer_Count=0;
			Buzzer_Flag=!Buzzer_Flag;
		}
	}
}

五.独立按键——三行代码消抖

前面的和状态机消抖一样,但是需要在.h文件中额外定义两个外部变量Trg和Cont,除此之外还要在.c文件再次定义这两个变量。####切记宏定义的KB值别加分号
^ 为按位异或,即一样为0,不一样为1;&为按位与
当没有按键按下时:KEYPORT=0xff,ReadData=(KEYPORT)^0xff为0,所以在Trg中,0&任何数都得0,所以Trg=0,所以Cont也为0;
当按键KB1按下时:KEYPORT=0xfe,ReadData=(0xfe)^0xff,即 1111 1110 ^ 1111 1111 =0000 0001=0x01,即ReadData=0x01,Trg=0x01 & (0x01 ^ 0),即 0000 0001 & (0000 0001 ^0000 0000),按位运算,所以Trg=0x01;
当按键KB1松开时:KEYPORT=0xff,ReadData=(0xff)^0xff=0,Trg也等于0,Cont也等于0
当按键KB2按下时:KEYPORT=0xfd,ReadData=(0xfd)^0xff,即 1111 1101 ^ 1111 1111 = 0000 0010=0x02,即ReadData=0x02,Trg=0x02 & (0x02 ^ 0),即 0000 0010 & (0000 0010 ^ 0000 0000),按位运算,所以Trg=0x02;
所以可以看出,可以通过查看Trg的值看是否有按键按下,0x01为第一个按键,0x02为第二个,以此类推
###注意ReadData=(KEYPORT)^ 0xff,这个KEYPORT必须带括号,因为KEYPORT =KB1|(KB2<<1)|(KB3<<2)|(KB4<<3)|0xf0 如果不加括号,C语言默认的是直接替换即KB1|(KB2<<1)|(KB3<<2)|(KB4<<3)|0xf0^ 0xff,因为异或的运算等级高,所以会0xf0^0xff先计算,会导致错误

key.c
#include "key.h"
#include "stm32f10x.h"
void KEY_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_8;
	//GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_2;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
}
key.h
#ifndef __KEY_H
#define __KEY_H

void KEY_Config(void);
#endif
key_threeline.c
#include "key_threeline.h"
#include "stm32f10x.h"
unsigned char Cont;
unsigned char Trg;
void Key_Threeline(void)
{
    unsigned char ReadData=(KEYPORT)^0xff;
	Trg=ReadData&(ReadData^Cont);
	Cont=ReadData;
}
key_threeline.h
#ifndef __KEY_THREELINE_H
#define __KEY_THREELINE_H
#define KB1 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)
#define KB2 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8)
#define KB3 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1)
#define KB4 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_2)
#define KEYPORT  KB1|(KB2<<1)|(KB3<<2)|(KB4<<3)|0xf0
void Key_Threeline(void);
extern unsigned char Cont;
extern unsigned char Trg;
#endif
timer.c
#include "timer.h"
#include "stm32f10x.h"
#include "stm32f10x_tim.h"
void NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	
	NVIC_Init(&NVIC_InitStructure);
}
void TIM2_Config(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	NVIC_Config();
	TIM_TimeBaseInitStructure.TIM_Prescaler=71;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period=999;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=0;
	//TIM_TimeBaseInitStructure.TIM_RepetitionCounter=;
	
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
	
	TIM_Cmd(TIM2,ENABLE);
}
timer.h
#ifndef __TIMER_H
#define __TIMER_H

void NVIC_Config(void);
void TIM2_Config(void);
#endif
main.c
#include "stm32f10x.h"
#include "lcd.h"
#include "buzzer.h"
#include "timer.h"
#include "key_state.h"
#include "key.h"
#include "key_threeline.h"
extern unsigned char Bool=0;
u32 TimingDelay = 0;

void Delay_Ms(u32 nTime);

//Main Body
int main(void)
{
	u8 key_value;
	SysTick_Config(SystemCoreClock/1000);

	Delay_Ms(200);

    Led_Init();
	KEY_Config();
	TIM2_Config();
	while(1)
	{
	    if(Bool==1)
		{
		    Bool=0;
			Key_Threeline();
			if(Trg==0x01)
			{
			    Led_Control(0x01,0);
			}
			if(Trg==0x02)
			{
			    Led_Control(0x01,1);
			}
		}
	}
}
void TIM2_IRQHandler(void)
{
	static unsigned char count=0;
    if(TIM_GetITStatus(TIM2, TIM_IT_Update)!=RESET)
	{
	    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
		count++;
		if(count==5)
		{
		    count=0;
			Bool=1;
		}
	}
}
//
void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

六.IIC协议

IIC通信协议:有SCL,SDA两条线,在启动IIC时,要在SCL高电平期间SDA由高电平向低电平转化,关闭IIC时,要在SCL高电平期间把SDA从低拉高

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

写数据:在写入一个字节的时候先打开IIC,然后写入AT24C02的固定地址和可配置地址还有一位读写的01构成的八位的地址,固定地址为1010,可配置地址为000,写为0,读为1,然后每次发送一个数据就要接收一个应答,接受一个数据就要发送一个应答,所以要接受一个应答,然后写入存储数据的地址,即EEPROM中有从0到255的位置都可以存储数据,看要把数据存放在哪,单片机就可以知道在哪里操作,再接收一个应答,发送要发送的数据再接收一个应答,最后停止IIC
读数据:在写入一个字节的时候先打开IIC,然后写入AT24C02的固定地址和可配置地址还有一位读写的01构成的八位的地址,接受一个应答,写入存储数据的地址,接受一个应答,就可以让单片机找到要在哪里读写数据,然后再打开IIC,然后写入AT24C02的固定地址和可配置地址还有一位读的1,单片机就可以知道是要读数据,接收一个应答,然后读出数据,发送一个应答,结束IIC
每次接收应答的时候默认可以正常接收到应答,只调用一下,不接收返回值,注意传参的时候,写数据要传入存储地址和数据,读数据的时候要传入存储地址。
******不能在中断中用IIc保存数据,应该在中断中用个变量置一,在中断外部保存数据

i2c.c
/*
  程序说明: CT117E嵌入式竞赛板GPIO模拟I2C总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT117E嵌入式竞赛板
  日    期: 2011-8-9
*/

#include "stm32f10x.h"
#include "i2c.h"
/** I2C 总线接口 */
#define I2C_PORT GPIOB
#define SDA_Pin	GPIO_Pin_7
#define SCL_Pin GPIO_Pin_6

#define FAILURE 0
#define SUCCESS 1

#define SLAVE_ADDRESSW 0xA0
#define SLAVE_ADDRESSR 0xA1

//配置SDA信号线为输入模式
void SDA_Input_Mode()
{
	GPIO_InitTypeDef GPIO_InitStructure;

	GPIO_InitStructure.GPIO_Pin = SDA_Pin;
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;	 

  	GPIO_Init(I2C_PORT, &GPIO_InitStructure);
}

//配置SDA信号线为输出模式
void SDA_Output_Mode()
{
	GPIO_InitTypeDef GPIO_InitStructure;

	GPIO_InitStructure.GPIO_Pin = SDA_Pin;
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

  	GPIO_Init(I2C_PORT, &GPIO_InitStructure);
}

//
void SDA_Output( uint16_t val )
{
	if ( val ) {
		GPIO_SetBits(I2C_PORT,SDA_Pin);
	} else {
		GPIO_ResetBits(I2C_PORT,SDA_Pin);
	}
}

//
void SCL_Output( uint16_t val )
{
	if ( val ) {
		GPIO_SetBits(I2C_PORT,SCL_Pin);
	} else {
		GPIO_ResetBits(I2C_PORT,SCL_Pin);
	}
}

//
uint8_t SDA_Input()
{
	return GPIO_ReadInputDataBit( I2C_PORT, SDA_Pin);
}

//延时程序
void delay1(unsigned int n)
{
	unsigned int i;
	for ( i=0;i<n;++i);
}

//I2C总线启动
void I2CStart(void)
{
	SDA_Output(1);delay1(500);
	SCL_Output(1);delay1(500);
	SDA_Output(0);delay1(500);
	SCL_Output(0);delay1(500);
}

//I2C总线停止
void I2CStop(void)
{
	SCL_Output(0); delay1(500);
	SDA_Output(0); delay1(500);
	SCL_Output(1); delay1(500);
	SDA_Output(1); delay1(500);

}

//等待应答
unsigned char I2CWaitAck(void)
{
	unsigned short cErrTime = 5;
	SDA_Input_Mode(); 
	delay1(500);
	SCL_Output(1);delay1(500);
	while(SDA_Input())
	{
		cErrTime--;
		delay1(500);
		if (0 == cErrTime)
		{
			SDA_Output_Mode();
			I2CStop();
			return FAILURE;
		}
	}
	SDA_Output_Mode();
	SCL_Output(0);delay1(500); 
	return SUCCESS;
}

//发送应答位
void I2CSendAck(void)
{
	SDA_Output(0);delay1(500);
	delay1(500);
	SCL_Output(1); delay1(500);
	SCL_Output(0); delay1(500);

}

//
void I2CSendNotAck(void)
{
	SDA_Output(1);
	delay1(500);
	SCL_Output(1); delay1(500);
	SCL_Output(0); delay1(500);

}

//通过I2C总线发送一个字节数据
void I2CSendByte(unsigned char cSendByte)
{
	unsigned char  i = 8;
	while (i--)
	{
		SCL_Output(0);delay1(500); 
		SDA_Output(cSendByte & 0x80); delay1(500);
		cSendByte += cSendByte;
		delay1(500); 
		SCL_Output(1);delay1(500); 
	}
	SCL_Output(0);delay1(500); 
}

//从I2C总线接收一个字节数据
unsigned char I2CReceiveByte(void)
{
	unsigned char i = 8;
	unsigned char cR_Byte = 0;
	SDA_Input_Mode(); 
	while (i--)
	{
		cR_Byte += cR_Byte;
		SCL_Output(0);delay1(500); 
		delay1(500); 
		SCL_Output(1);delay1(500); 
		cR_Byte |=  SDA_Input(); 
	}
	SCL_Output(0);delay1(500); 
	SDA_Output_Mode();
	return cR_Byte;
}

//I2C总线初始化
void i2c_init()
{
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

	GPIO_InitStructure.GPIO_Pin = SDA_Pin | SCL_Pin;
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	 // **

  	GPIO_Init(I2C_PORT, &GPIO_InitStructure);

}
//自己写的
unsigned char Write_AT24C02(uint16_t WORD_ADDRESS , uint16_t Data)
{
    I2CStart();
	I2CSendByte(SLAVE_ADDRESSW);
	I2CWaitAck();
	I2CSendByte(WORD_ADDRESS);
	I2CWaitAck();
	I2CSendByte(Data);
	I2CWaitAck();
	I2CStop();
}
unsigned char Read_AT24C02(uint16_t WORD_ADDRESS)
{
	unsigned char Data;
    I2CStart();
	I2CSendByte(SLAVE_ADDRESSW);
	I2CWaitAck();
	I2CSendByte(WORD_ADDRESS);
	I2CWaitAck();
	I2CStart();
	I2CSendByte(SLAVE_ADDRESSR);
	I2CWaitAck();
	Data=I2CReceiveByte();
	I2CSendAck();
	I2CStop();
	return Data;
}

i2c.h
#ifndef  __I2C_H__
#define  __I2C_H__

void i2c_init(void);
void delay1(unsigned int n);

void I2CStart(void);
void I2CStop(void);
void I2CSendAck(void);
void I2CSendNotAck(void);
unsigned char I2CWaitAck(void);

void I2CSendByte(unsigned char cSendByte);
unsigned char I2CReceiveByte(void);

#endif

#include "stm32f10x.h"
#include "lcd.h"
#include "buzzer.h"
#include "led.h"

u32 TimingDelay = 0;
_Bool Buzzer_flag=0;
void Delay_Ms(u32 nTime);

//Main Body
int main(void)
{
	u16 index;
	SysTick_Config(SystemCoreClock/1000);

	Delay_Ms(200);
	Led_Init();
	Buzzer_Init();
	i2c_init();
	
	Buzzer_flag=Read_AT24C02(0x00);
	Buzzer_flag=!Buzzer_flag;
	if(Buzzer_flag)
	{
	    Buzzer_ON;
	}
	else
	{
	    Buzzer_OFF;
	}
	Write_AT24C02(0x00 ,Buzzer_flag);
	while(1)
	{
		
	}
}

//
void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

七.LCD显示

至于lcd显示,只需要知道几个常用函数即可:
STM3210B_LCD_Init(void);用来初始化lcd
LCD_SetTextColor(vu16 Color);用来设置从这句代码执行之后的文字颜色
LCD_SetBackColor(vu16 Color);用来设置从这句代码执行之后的背景颜色
LCD_Clear(u16 Color);用来设置以什么颜色清屏
LCD_DisplayStringLine(u8 Line, u8 *ptr);来设置在哪行显示什么字符,通常与sprintf函数搭配使用

void Display_eeprom(uint16_t eeprom)
{
    uint8_t temp[20];
	sprintf(temp,"eeprom is %d",eeprom);
	LCD_DisplayStringLine(Line0,temp);
}

八.串口接收与发送

USART串口通信:RBT6有两个USART,一个USART对应一对RX、TX引脚,RBT6上有两对,RX1、TX1对应USART1,RX2、TX2对应USART2,可以用于单片机向电脑发送数据,电脑通过串口助手打印电脑收到的数据,也可以电脑通过串口助手向单片机发送数据,单片机再把收到的数据发向电脑看是否单片机正确接收到了数据。串口也可以再程序的关键点检查错误,如果程序运行到那里,就发送OK

USART只发送数据:查看原理图上需要使用的USARTx对用的TXx和RXx,然后初始化引脚GPIO的结构体,如果使用USART2的话打开时钟时不仅打开GPIO时钟,还要打开AFIO的时钟,在使用USART的情况下,TX对应的引脚要配置成复用功能的推挽输出,RX对应的引脚要配置成浮空输入,然后配置USART的结构体,USART_BaudRate为波特率,根据题目要求配置波特率,只有波特率一样才能在统一频道通信,USART_WordLength为字长,有八位九位字长,一般为八位字长,USART_StopBits为停止位,有一位,半位,两位,一点五位,一般为一位,USART_Mode位通信模式,通过设置通信模式来设置是接收数据还是发送数据,USART_HardwareFlowControl来指定硬件流量控制模式是启用还是禁用,一般是禁用,然后初始化USART结构体,然后使用USART_Cmd(
)来打开USART。
自定义函数发送:发送数据的方式有两种,其中一种是自己书写发送函数,以发送字符串为例,形参设置为字符串的地址,以地址来取字符串,用USART_SendData(USART2, *s++)来一个字母一个字母,一位一位的发送,*s在自增运算符++的左边,表示先用后加,指针默认指向字符串的第一个字母,然后逐渐往后移,USART_GetFlagStatus()来判断中断标志位状态,在发送数据的时候中断标志位设置为检测USART_FLAG_TXE也就是发送数据的空标志位,每次数据发送出去这个标志位就清零,如果清零,就说明这一位数据已发送,该发送下一位数据了,再通过循环发送下一位数据,用while判断数据有没有发送完,如果字符型数据发送完,字符型数据后面有\0,即可跳出循环。主函数调用即可SendStr(“hello”)

usart.c
#include "usart.h"
#include "stm32f10x.h"
void usart_config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	
	 GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	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_Mode=USART_Mode_Tx|USART_Mode_Rx;
	USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
	
	USART_Init(USART2, &USART_InitStructure);
	
	USART_Cmd(USART2, ENABLE);
}
void SendStr(char *s)
{
	while(*s)
	{
	    USART_SendData(USART2, *s++);
        while(USART_GetFlagStatus(USART2, USART_FLAG_TXE)==RESET)
	    { }
	}
}
usart.h
#ifndef __USART_H
#define __USART_H
void usart_config(void);
void SendStr(char *s);
#endif
main.c
#include "stm32f10x.h"
#include "lcd.h"
#include "buzzer.h"
#include "led.h"
#include "usart.h"
u32 TimingDelay = 0;

void Delay_Ms(u32 nTime);

//Main Body
int main(void)
{
	u16 index;
	SysTick_Config(SystemCoreClock/1000);
    
	Delay_Ms(200);
	Led_Init();
	Buzzer_Init();
	usart_config();
	SendStr("hello");
	while(1)
	{

	}
}


//
void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

C语言库发送:在固件库\stm32f10x_stdperiph_lib\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\USART\Printf\main.c 文件中复制以int fputc(int ch, FILE *f)为函数名,图示下方语句为函数体的函数,并将原有函数体中参数改变,改为如图所示,切记将中断标志位都换位发送非空中断,即USART_FLAG_TXE,因为原有的C语言的函数不能在keil中直接使用,要添加头文件 #include “stdio.h” ,并且要将魔术棒中Use MicroLIB勾选,使用微库才可以正常使用,然后可以像原有C语言中的printf一样使用
####使用printf必须使用微库,不然会导致代码无法运行
在这里插入图片描述

USART接收数据:在初始化USART时,除了要配置上面的GPIO,USART结构体之外,还要配置NVIC来初始化USART串口中断,与定时器中断不太一样,然后在main函数中写入USART中断函数,应为这是接收数据,所以要判断接收数据寄存器非空标志位,每次接收一个数据,非空标志位就置1,用USART_GetITStatus()函数来判断非空标志位是不是RESET,如果不是,说明单片机接收到了数据,,然后要清除这个标志位,用来判断下一位数据是否正常发送,清除数据位之后,用一个数组逐位接收USART接收到的数据,用自己定义的计数变量来推后数组引用,因为这是接收数据,无法通过串口助手直接看到,所以在串口中断中再将接受到的数据返回给电脑,用于检查程序是否错误,这也是USART的一个作用
****在接收数据时,尤其是字符串,接收寄存器不会接收到字符串最后的“\0”,或者说可以接收到,但是“\0”并不占数组的一位

usart.c
#include "stdio.h"
#include "usart.h"
void Usart_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;
	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_3;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	USART_InitStructure.USART_BaudRate=115200;
	USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
	USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Parity=USART_Parity_No;
	USART_InitStructure.USART_StopBits=USART_StopBits_1;
	USART_InitStructure.USART_WordLength=USART_WordLength_8b;
	USART_Init(USART2, &USART_InitStructure);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	NVIC_InitStructure.NVIC_IRQChannel=USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure); 
	
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
	
	USART_Cmd(USART2, ENABLE);
}
int fputc(int ch, FILE *f)
{
      /* Place your implementation of fputc here */
  /* e.g. write a character to the USART */
  USART_SendData(USART2, (uint8_t) ch);

  /* Loop until the end of transmission */
  while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET)
  {}

  return ch;
}

usart.h
#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
#include "stdio.h"
void Usart_Config(void);

#endif
main.c
#include "stm32f10x.h"
#include "lcd.h"
#include "buzzer.h"
#include "led.h"
//#include "stdio.h"
#include "usart.h"
u32 TimingDelay = 0;

void Delay_Ms(u32 nTime);

//Main Body
int main(void)
{
	u16 index;
	SysTick_Config(SystemCoreClock/1000);
	
	Delay_Ms(200);
	Led_Init();
	Buzzer_Init();
    Usart_Config();
	printf("hello %d",10);

	while(1)
	{
	}
}
u8 rx_buf[10];
char rx_count=0;
int i=0;
void USART2_IRQHandler(void)
{
    if(USART_GetITStatus(USART2, USART_IT_RXNE)!=RESET)
	{
	    USART_ClearITPendingBit(USART2, USART_IT_RXNE);
		rx_buf[rx_count++]=USART_ReceiveData(USART2);
        if((rx_buf[4]!=0)&&i==0)
	    {
	        printf("%s",rx_buf);
			i++;
	    }
	}
}

void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

九.ADC采样

ADC数模转换:RBT6有ADC1,ADC2两个ADC,每个ADC有16个通道,通过下图所示PB0接滑动变阻器,滑到最上为3.3v,滑到最下为0v,将0到3.3v的电压映射到0到4096,即2的12次方,通过采集到的值反馈当前电压值。

在这里插入图片描述

首先初始化GPIO,注意将GPIO模式设置为模拟输入,几乎是ADC专用模式,在输入模式下不需要设置速度,下来配置ADC结构体时候先打开时钟,然后配置结构体:
ADC_Mode为ADC模式,有单双通道模式,即单个ADC还是两个ADC
ADC_ScanConvMode为扫描模式指定是在扫描(多通道)模式还是单通道(单通道)模式下执行转换,一般配置为ENABLE即可
ADC_ContinuousConvMode为是否配置持续扫描模式,一般配置为ENABLE,否则只扫描一次,使能后会持续一直扫描ADC_ExternalTrigConv为定义用于启动常规通道的模数转换的外部触发器,一般配置为没有,即ADC_ExternalTrigConv_None
ADC_DataAlign设置对齐方式设置为右对齐ADC_DataAlign_Right即可

ADC_NbrOfChannel为设置需要使用的ADC通道数,一个ADC有16个通道,需要用几个就配置几个
然后初始化结构体,如果设置了ADC中断,接下来就要用ITConfig来使能中断,
ADC_RegularChannelConfig通过这个函数来配置规则通道的ADC通道和转换顺序和采样时间,准换顺序在只有一个ADC的时候没用,所以配置成1即可,采样时间随便配置一个即可ADC_SampleTime_55Cycles5就行,然后用Cmd使能ADC,然后通过ADC_ResetCalibration来复位校准寄存器,用while函数嵌套ADC_GetResetCalibrationStatus来等待ADC校准寄存器复位完成,再用ADC_StartCalibration来进行ADC校准,同样使用while嵌套ADC_GetCalibrationStatus来等待ADC采样完成,最后用ADC_SoftwareStartConvCmd用软件开始ADC采样。

使用了中断以后,在写中断函数时老套路用ADC_GetITStatus检查ADC_IT_EOC也就是规则通道的中断是不是来了,如果中断来了这个位就会置位成SET,ADC_IT_AWD则是注入通道的中断,然后用ADC_ClearITPendingBit这个函数来清除中断标志位,以便于接收下一次中断,然后可以用ADC_GetConversionValue来读取ADC中接收到的值

adc.c
#include "adc.h"
#include "stm32f10x.h"
void GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
	
	GPIO_Init(GPIOB,&GPIO_InitStructure);
}
void ADC_Config(void)
{
    ADC_InitTypeDef ADC_InitStructure;
	GPIO_Config();
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	
	ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStructure.ADC_ScanConvMode= DISABLE;
	ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;
	ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfChannel=1;
	
	ADC_Init(ADC1,&ADC_InitStructure);
	RCC_ADCCLKConfig(RCC_PCLK2_Div8);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_55Cycles5);
	//ADC_ITConfig(ADC1,ADC_IT_EOC,ENABLE);有中断时使用  
	ADC_DMACmd(ADC1, ENABLE);	
	ADC_Cmd(ADC1,ENABLE);
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1));
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1));
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}
adc.h
#ifndef __ADC_H
#define __ADC_H
void GPIO_Config(void);
void ADC_Config(void);

#endif
main.c
#include "stm32f10x.h"
#include "lcd.h"
#include "buzzer.h"
#include "led.h"
#include "adc.h"
u32 TimingDelay = 0;

void Delay_Ms(u32 nTime);

//Main Body
uint32_t value;
void LCD_Show(uint32_t value)
{
    char buffer[20];
	sprintf(buffer,"value is %d",value);
	LCD_DisplayStringLine(Line2,buffer);
}
int main(void)
{
	
	u16 index;
	SysTick_Config(SystemCoreClock/1000);

	Delay_Ms(200);
	
	ADC_Config();
	STM3210B_LCD_Init();
	LCD_Clear(Black);
	LCD_SetTextColor(Red);
	LCD_SetBackColor(Black);
	while(1)
	{
		value=ADC_GetConversionValue(ADC1);    
          LCD_Show(value);
	}
}

//
void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

十.RTC时钟

RTC实时时钟:单片机内部有一块掉电不丢失的寄存器(由额外电池(纽扣电池)供电),RTC模块的一些配置是被一个叫做后备区域保护着(禁止写),所以设置之前要先取消后背区域写保护。RTC和普通定时器不一样的地方:RTC模块和时钟配置系统是在后备区域,即在系统复位或从待机模式唤醒后,RTC的设置和时间维持不变。但在系统复位后会禁止访问后备寄存器和RTC,以防止对后备区域的意外操作,所以在设置RTC之前要去掉备份区域写保护。

RTC配置:先配置好NVIC的RTC中断,然后开始正式配置RTC,首先将RCC_APB1Periph_PWR | RCC_APB1Periph_BKP这两个的时钟配置好,即打开给RTC供电的电源和备份区域的时钟,用PWR_BackupAccessCmd(ENABLE)来使能后备电源,使用BKP_DeInit()来复位备份区域,因为RBT6没有外部晶振,所以只能使用LSI作为时钟来源,用RCC_LSICmd(ENABLE)来打开LSI为时钟,使用while循环来判断LSI低速时钟是否准备就绪,即while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET),再通过RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI)来设置LSI作为RTC时钟来源,上面那个是打开LSI时钟,这个是把LSI作为RTC的时钟,再通过RCC_RTCCLKCmd(ENABLE)来使能RTC时钟,再通过RTC_WaitForLastTask()来等待最近一次对RTC寄存器的写操作完成,通过RTC_WaitForSynchro()来等待RTC寄存器同步,然后使用RCC的ITConfig来使能中断,参数设置为RTC_IT_SEC来设置为秒中断,一秒记一次时,继续通过RTC_WaitForLastTask()来等待最近一次对RTC寄存器的写操作完成,通过RTC_SetPrescaler(40000)来配置预分频系数,继续用上述RTC函数RTC_WaitForLastTask()来等待写完成,使用BKP_TamperPinCmd(DISABLE);来禁用防篡改功能,最受使能NVIC即可

初始化时间值:先让RTC等待上次写操作完成,使用RTC_SetCounter(Tmp_HH3600 + Tmp_MM60 + Tmp_SS)来写入初始化以后的时间,因为是输入参数是秒,所以将其设置为三个形参的函数,分别输入时分秒,然后在括号中将其转换成秒,最后再调用一次等待写操作函数

在LCD显示时间:向函数传入参数,参数应为秒数,先在函数中用RTC_GetCounter()这个函数的返回值来判断是不是等于23:59:59这个时间的秒数的十六进制值即 0x1517F,如果等于的话,将时间再通过RTC_SetCounter(0x0)来重置为0,然后等待写操作完成,然后用除法把输入的形参拆分成时分秒,然后用printf来显示。

RTC的中断配置:老规矩用GetITStatus来判断RTC_IT_SEC秒中断是否已经不是RESET,即中断位已经置一,如果已经置一,则清除中断位以后写入要写的操作,然后再次调用函数等待写操作完成

在主函数中先调用函数将时间初始化,然后再通过调用Display函数把用GetCounter返回的值显示出来,因为中断一直在更新,所以函数返回值也在一直更新,所以时间显示出来也在一直更新

rtc.c
#include "rtc.h"
#include "stm32f10x.h"
#include "stdio.h"
void Rtc_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP|RCC_APB1Periph_PWR,ENABLE);
	PWR_BackupAccessCmd(ENABLE);
	BKP_DeInit();
	RCC_LSICmd(ENABLE);
	while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)==RESET);
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
	RCC_RTCCLKCmd(ENABLE);
	RTC_WaitForLastTask();
	RTC_WaitForSynchro();
	RTC_ITConfig(RTC_IT_SEC, ENABLE);
	RTC_WaitForLastTask();
	RTC_SetPrescaler(40000);
	RTC_WaitForLastTask();
	BKP_TamperPinCmd(DISABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	NVIC_InitStructure.NVIC_IRQChannel=RTC_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}
void Time_Adjust(u8 HH,u8 MM,u8 SS)
{
    RTC_WaitForLastTask();
	RTC_SetCounter(HH*3600+MM*60+SS);
	RTC_WaitForLastTask();
}
void Time_Display(uint32_t Time)
{
	u8 HH=0,MM=0,SS=0;
    if(RTC_GetCounter()==0x0001517F)
	{
	    RTC_SetCounter(0x0);
		RTC_WaitForLastTask();
	}
	HH=Time/3600;
	MM=(Time%3600)/60;
	SS=(Time%3600)%60;
	printf("Time:%d:%d:%d\n",HH,MM,SS);
}
rtc.h
#ifndef __RTC_H
#define __RTC_H
#include "stm32f10x.h"
void Rtc_Config(void);
void Time_Adjust(u8 HH,u8 MM,u8 SS);
void Time_Display(uint32_t Time);

#endif
main.c
#include "stm32f10x.h"
#include "lcd.h"
#include "buzzer.h"
#include "led.h"
#include "usart.h"
u32 TimingDelay = 0;
_Bool flag=0;
void Delay_Ms(u32 nTime);

//Main Body
int main(void)
{
	u16 index;
	SysTick_Config(SystemCoreClock/1000);

	Delay_Ms(200);
	Rtc_Config();
	Time_Adjust(23,50,50);
	while(1)
	{
		if(flag==1)
		{
		    Time_Display(RTC_GetCounter());
			flag=0;
		}
	}
}
void RTC_IRQHandler(void)
{
    if(RTC_GetITStatus(RTC_IT_SEC)!=RESET)
	{
	    RTC_ClearITPendingBit(RTC_IT_SEC);
		flag=1;
		RTC_WaitForLastTask();
	}
}
//
void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

十一.PWM输出及输入捕获

PWM输出与输入捕获:PWM波通过定时器产生,STM32 的定时器除了基本定时器 TIM6 和 TIM7。其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4路的 PWM 输出,这样,STM32 最多可以同时产生 30 路 PWM 输出。以下为STM32所有的定时器的输出PWM的通道对应的端口

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

PWM输出:首先打开时钟,这里以TIM2的第二个通道为例,即PA1口,因为PA1口对应不仅有TIM2的通道,还有TIM5的通道,所以打开时钟的时候不仅要打开定时器和GPIO的时钟,还要打开AFIO端口复用的时钟,再配置GPIO的结构体时,要将模式设置为复用推挽输出,然后接下来配置TIM的定时器功能的结构体,即TIM_TimeBaseInitTypeDef:
TIM_Prescaler:配置预分频系数Prescaler = (TIM3CLK / TIM3 counter clock) - 1,在官方解释中The TIM3CLK frequency is set to SystemCoreClock (Hz), to get TIM3 counter clock at 24 MHz the Prescaler is computed as following,即TIM3CLK=SystemCoreClock,TIM3 counter clock=24MHz,即可得出预分频系数,
TIM_Period:定时器周期,实际就是设定自动重载寄存器的值,在官方解释中The TIM3 is running at 36 KHz: TIM3 Frequency = TIM3 counter clock/(ARR + 1) = 24 MHz / 666 = 36 KHz,即TIM3应该是36KHz的速度运行,因为TIM3 counter clock即TIM3的时钟为24MHz,要想让TIM3以36KHz的速度运行,就应该配置666为一个周期,又因为从0开始计数,所以设置TIM_Period为665
再配置管理PWM输出的结构体TIM_OCInitTypeDef:
TIM_OCMode:配置输出的模式,常用有TIM_OCMode_PWM1和TIM_OCMode_PWM2:
TIM_OCMode_PWM1:在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为 无效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否 则为有效电平(OC1REF=1)。
TIM_OCMode_PWM2:在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为 有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电 平。以PWM2为例,图示斜线为TIM中的计时器,随时间而增长,增长到ARR之后回到0重新计时,当小于CCRx时为无效电平,当大于CCRx为有效电平。
TIM_OutputState:用来让输出状态为使能OC输出。
TIM_OutputNState:用来指定输出比较状态,但是只对TIM1和TIM8适用,一般不用
TIM_Pulse:设置脉冲宽度,左图为计算占空比的方法,即CCRx与ARR的比值,因为在上面已将说到了以CCRx为界来看有效电平和无效电平,所以如果CCR为ARR的一半,刚好占空比就是百分之五十, 而ARR为计数的最高点,TIM_Period为一个周期的值,也就是ARR的值,ARR为666,要想获得一个占空比为百分之五十的波形,那么就要设置TIM_Pulse为333。
TIM_OCPolarity:设置输出比较极性,TIM_OCPolarity_High或者TIM_OCPolarity_Low两种,实际输出的电平是由输出极性和电平有效共同决定的,左图为极性和电平的有效来控制灯的点亮的不同情况,根据所有情况可以知道当高极性对应有效电平可以输出高电平,低极性和无效电平可以输出高电平,其余不是这样对应的都是低电平。
然后调用TIM_OCxInit()来初始化结构体,其中x为要使用的定时器的PWM第x个通道,然后调用TIM_OC2PreloadConfig(),该函数是设置使能寄存器TIM_CCMR1的OC2PE位,该位是开启/禁止TIMx_CCR1寄存器的预装载功能,TIMx_CCRx寄存器能够在任何时候通过软件进行更新以控制波形,这个通过软件写入控制波形的值是立即生效还是在定时器发生下一次更新事件时被更新的,就是由这个函数决定的,然后调用函数TIM_ARRPreloadConfig(),这个函数是允许或禁止在定时器工作时向ARR的缓冲器中写入新值,以便在更新事件发生时载入覆盖以前的值,最后用Cmd函数来使能定时器,主函数调用即可
在主函数中可以调用TIM_SetComparex()函数来设置CRR寄存器的值,CRR即高低电平分界线,若在这里设置为222,根据上面的配置,ARR为666,则占空比为三分之一,若设置为333,则占空比为二分之一。还可以通过TIM_SetAutoreload()来设置ARR的值,即重装载值,TIM_SetComparex()来设置CRR为500,用TIM_SetAutoreload()来设置ARR为1000,那么占空比就是二分之一

PWM输入捕获:首先开启定时器时钟和GPIO时钟,在输入捕获时不管哪个管脚都不需要开启复用时钟,然后初始化GPIO结构体,因为要输入捕获,所以要设置为浮空输入,然后初始化输入捕获的结构体TIM_ICInitTypeDef,
TIM_Channel:设置捕获通道
TIM_ICPolarity:设置上升沿捕获还是下降沿捕获
TIM_ICSelection:用来设置映射关系,设置为直连还是非直连,每个定时器有四个输入通道,IC1,IC2,IC3,IC4,其中IC1和IC2为一组,IC3与IC4一组,在PWM输入捕获中,只用通道一和通道二,即IC1和IC2,而IC3与IC4不用,如果使用通道一,将TI1FP1设置为触发点,那么IC1将捕获周期,IC2将捕获占空比,这就是直连,如果TI1FP2设置为触发点,IC2将捕获周期,IC1将捕获占空比,此为非直连。所以看直连非直连只需要看图中捕获周期的线是直的还是弯的,直的就是直连,弯的就是非直连。
TIM_ICPrescaler:设置输入捕获分频系数,不分频则每次触发信号都捕获,2分频即两次触发信号才捕获
TIM_ICFilter:设置滤波器长度,设置为0x0即可
然后用TIM_PWMIConfig函数来初始化结构体,再用TIM_SelectInputTrigger()来选择输入捕获的触发信号,即告诉定时器上升沿来了开始捕获,始终将触发点设置为捕获周期的那一个,再根据设置的直连非直连具体看是设置哪个,因为这个程序中设置通道二捕获,且为直连,所以TI2FP2将捕获周期,所以出发点设置为TIM_TS_TI2FP2,这个寄存器在捕获的时候会捕获到周期,一旦捕获到周期然后就触发,然后用TIM_SelectSlaveMode()来选定复位模式为从模式,再用TIM_SelectMasterSlaveMode()函数来设置使能主从模式,然后接下来Cmd和ITConfig来配置TIM定时器,注意在调用ITConfig的时候,要将第二个参数设置为TIM使用的捕获通道,使用的第几个通道就是CC几,在用定时器的功能的时候才使用Update,除此之外还要配置NVIC中断。
中断函数:不同于之前定时器,进入中断不再判断是否中断标志位是否置位,直接清除中断标志位,然后要先取出周期值,根据配置的直连非直连和必须先取出周期值的要求决定是用TIM_GetCapture1还是TIM_GetCapture2函数来取出周期值,剩下的那个就用来取出占空比,在这个程序中时通道二采取的是直连,并且TI2FP2存储周期,所以要用TIM_GetCapture2来取出周期,进行计算。

在这里插入图片描述

timer.c
#include "timer.h"
#include "stm32f10x.h"
void TIM2_PWM_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	uint16_t Prescaler=(uint16_t)(SystemCoreClock/24000000)-1;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_TimeBaseInitStructure.TIM_Prescaler=Prescaler;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period=665;
	TIM_TimeBaseInitStructure.TIM_ClockDivision=0;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
	
	TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_Pulse=333;
	TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
	TIM_OC2Init(TIM2,&TIM_OCInitStructure);
	TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);
	TIM_ARRPreloadConfig(TIM2, ENABLE);
	TIM_Cmd(TIM2,ENABLE);
}
void TIM3_PWM_INPUT_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	TIM_ICInitTypeDef TIM_ICInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;
	TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
	TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;
	TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;
	TIM_ICInitStructure.TIM_ICFilter=0x0;
	TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1 );//
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
	TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);
	TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);//
	TIM_Cmd(TIM3, ENABLE);

}
timer.h
#ifndef __TIMER_H
#define __TIMER_H
void TIM2_PWM_Config(void);
void TIM3_PWM_INPUT_Config(void);

#endif
main.c
#include "stm32f10x.h"
#include "lcd.h"
#include "buzzer.h"
#include "led.h"

u32 TimingDelay = 0;

void Delay_Ms(u32 nTime);

//Main Body
int main(void)
{
	u16 index;
	SysTick_Config(SystemCoreClock/1000);

	Delay_Ms(200);
	TIM2_PWM_Config();
	TIM3_PWM_INPUT_Config();
	while(1)
	{
		
	}
}
__IO uint32_t IC2value=0;
__IO uint32_t DutyCycle=0;
__IO uint32_t Frequency=0;
void TIM3_IRQHandler(void)
{
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);//
	IC2value=TIM_GetCapture1(TIM3);
	if(IC2value!=0)
	{
	    DutyCycle=(TIM_GetCapture2(TIM3)*100)/IC2value;
		Frequency=SystemCoreClock/IC2value;
	}
	else
	{
	    DutyCycle=0;
		Frequency=0;
	}
}
//
void Delay_Ms(u32 nTime)
{
	TimingDelay = nTime;
	while(TimingDelay != 0);	
}

对于输入捕获来说,直接用杜邦线把定时器2的2通道和定时器3的1通道连接然后读取相应值就可以知道周期与占空比。
对于输出模式来说,如果手边有示波器,直接把示波器一脚接IO口,一脚接地即可,如果手边没有示波器,那么可用keil自带的仿真查看波形

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

蓝桥杯嵌入式(STM32F103RBT6)备赛手册(一) 的相关文章

  • 商人过河--广度优先搜索--matlab实现

    进行了代码优化 目录 应用背景 xff1a 模型求解 xff1a 模型建立 xff1a 模型实现 xff1a 源代码 xff1a 运行结果 xff1a 附 xff1a 应用背景 xff1a M个商人与N个仆从过河 xff0c 小船一次可载k
  • C++---全局对象、局部对象、静态对象

    1 全局对象 xff0c 程序一开始 xff0c 其构造函数就先被执行 xff08 比程序进入点更早 xff09 xff1b 程序即将结束前其析构函数将被执行 2 局部对象 xff0c 当对象生成时 xff0c 其构造函数被执行 xff1b
  • 2011年B题交通巡警第一问的练习与实现

    题目要求 xff1a 试就某市设置交巡警服务平台的相关情况 xff0c 建立数学模型分析研究下面的问题 xff1a xff08 1 xff09 附件1中的附图1给出了该市中心城区A的交通网络和现有的20个交巡警服务平台的设置情况示意图 xf
  • 利用最大流最小割算法matlab割图

    目录 练习思路 matlab绘图 噪音 坐标编码 邻接矩阵 最大流最小割算法 对最大流最小割算法求解结果转换为图像 源代码 运行实例 TIPS 最近学习了最大流和最小割算法 xff0c 可以把图看成是一些点的集合 xff0c 色彩差值的倒数
  • 关于将一个数分解成四个数平方和的算法matlab

    目录 理论基础 拉格朗日四平方数和定理 高斯恒等式 操作步骤 分解质因数 求解四平方数 应用高斯恒等式 小结 高斯恒等式输出代码 输出结果 运行结果 怎么把一个大数分解成四个小数的平方和呢 xff1f 理论基础 拉格朗日四平方数和定理 每个
  • 寻找较大素数,简易实现RSA密码系统matlab

    目录 RSA密码系统 随机寻找两个较大的素数 欧拉筛的算法函数 寻找随机素数的代码 生成公钥和私钥 加密解密方式 实现代码 运行结果 小结 首先来了解一下什么是RSA算法 RSA密码系统 RSA是被研究得最广泛的公钥算法 xff0c 从提出
  • 关于返回一个矩阵中为0元素个数及位置的matlab自定义函数实现以及用到的matlab基本操作

    目录 练习例题 题目要求 代码呈现 运行结果 基础操作 返回矩阵的行数列数 生成矩阵函数 取整取余函数 自定义函数参数缺省下的默认值以及输入参数为空集下替换为默认值的情况 find函数大观 对于find函数的改善调用 练习例题 题目要求 编
  • 蓝桥杯——单片机学习(3——点亮LED灯)

    注 xff1a 此单片机型号为 STC15F2K60S2 原理 如图 xff0c 发光二极管L1 L8 共阳接法 xff0c VCC为电源正极 xff0c 高电平 已知发光二极管正向导通反向截至 xff0c 要使得二极管发光 xff0c 就
  • 蓝桥杯——单片机学习(5(1)——按键(独立按键))

    注 xff1a 此单片机型号为 STC15F2K60S2 目录标题 独立按键原理按键原理消抖 代码入门代码进阶代码消抖改进 xff08 按一下只执行一次 xff0c 长按也一样 xff09 补充 独立按键 原理 这是一个矩阵按键的电路图 x
  • 最全的蓝桥杯嵌入式备赛集合~

    机缘巧合 xff0c 报了嵌入式的比赛 xff08 我能说是老师逼我的吗 orz xff09 xff0c 由于从来没接触过 xff0c 所以还是先从查找资料开始 下面就是我查找的资料集合 博客 建议篇 64 summerrrrrrc 蓝桥杯
  • 关于STM32编译报错:Error: L6218E: Undefined symbol SystemInit (referred from startup_stm32f10x_md.o).

    今天新建工程发现出现一个错误 Output CG axf Error L6218E Undefined symbol SystemInit referred from startup stm32f10x md o 但我觉得我的操作没有任何问
  • 蓝桥杯嵌入式比赛知识点合集(现在什么都有好吧)

    目录 新建工程LCDsprintf格式输出百分号 输出格式 xff1a Rmemset函数LCD DisplayStringLine函数嘀嗒定时器高亮行高亮一两个字符高亮单个字节高亮使用 多个字节高亮使用 行闪烁使用 LEDdisplay函
  • google 和 firefox 添加用户自定义脚本

    如何在页面中嵌入自己写的Javascript脚本呢 xff1f 下面分别介绍一下在Chrome和Firefox两种浏览器上的操作步骤 xff1a Chrome xff1a 1 打开chrome扩展程序页 chrome extensions
  • JAVA开源解析HTML工具

    好东西收藏一下 原地址 xff1a http www open open com 30 htm NekoHTML NekoHTML是一个简单地HTML扫描器和标签补偿器 tag balancer 使得程序能解析HTML文档并用标准的XML接
  • 虚拟机中ubuntu系统联网问题——以桥接模式解决

    前因后果就不说了 xff0c 这里只记录方法 xff0c 希望未来再遇到这种问题可以及时解决 文章目录 我电脑的配置与环境解决方案 桥接模式打开已经连接的WiFi的属性 xff0c 记录IPv4的相关值打开虚拟网络编辑器 xff0c 设置桥
  • 无人机导航定位技术-复习

    文章目录 无线电导航 要求 精度 陆基导航 定义 塔康导航 TACAN 范围 天线 结构设计 信标方向 伏尔导航 VOR 定义 工作原理 建设要求 拓展 测距器 DME
  • 记录——golang版本更新代码

    环境 Ubuntu20 04 解决方法 方法一 xff1a 将旧版本的go卸载 xff0c 重新安装最新版本的go xff08 我使用且成功的 xff09 sudo apt get remove golang 1 span class to
  • ArcGIS10.6“License许可启动无响应”解决方法

    以下是我尝试过的方法 关闭防火墙 xff08 很必要 xff09 替换 Service txt 及 34 ARCGIS exe 34 文件 xff08 感觉没什么用 xff09 修改服务设置 xff08 很必要 xff09 更改注册表 xf
  • 学好网络编程注意的点

    注 xff1a 总结不完善后续继续总结 对于TCP连接 xff1a 1 服务器端1 xff09 创建套接字create xff1b 2 xff09 绑定端口号bind xff1b 3 xff09 监听连接listen xff1b 4 xff
  • C++中的.和:以及::还有->的区别

    1 A B则A为对象或者结构体 xff1b 2 A gt B则A为指针 xff0c gt 是成员提取 xff0c A gt B是提取A中的成员B xff0c A只能是指向类 结构 联合的指针 xff1b 3 是作用域运算符 xff0c A

随机推荐

  • C++静态库与动态库以及Windows上的创建以及使用

    一 什么是库 库是写好的现有的 xff0c 成熟的 xff0c 可以复用的代码 现实中每个程序都要依赖很多基础的底层库 xff0c 不可能每个人的代码都从零开始 xff0c 因此库的存在意义非同寻常 本质上来说库是一种可执行代码的二进制形式
  • C/C++ 函数的定义 声明 调用的区别

    C语言基础 xff1a 函数 xff08 定义函数 声明函数 调用函数 xff08 传值调用 引用调用 xff09 函数的参数 xff08 形参 实参 xff09 xff09 1 函数 函数是一组一起执行一个任务的语句 每个 C 程序都至少
  • jar包的处理

    用命令创建 jar命令详解 jar cf test jar test不显示压缩过程将当前路径下的test路径下的全部内容生成一个test jar文件 xff0c 如果已经存在则被覆盖 jar cvf test jar test显示压缩过程
  • Matlab2016及以上版本设置VS编译器

    Matlab2016及以上版本设置VS编译器 在Matlab中使用mex可以编译c c 43 43 xff0c 但是首先要设置好编译器 xff0c 可以使用mex setup命令来设置 如果电脑上是先安装的Visual Studio xff
  • Qt修改UI文件无效解决方案

  • win10关闭升级win11

    win10 11系统之中有一个令人厌倦的作用 xff0c 那便是自动升级 很多人会想起本来电脑上在应用全过程之中没什么难题 xff0c 系统却经常发生升级 xff0c 占用系统資源 xff0c 还会发生自动重启的状况 xff0c 又不可以放
  • 流程图、类图推荐的软件

    inux 下的绘图软件Visio 流程图 xff0c 矢量图 5款替代微软Visio的开源免费软件
  • 屏幕坏点检测

    屏幕坏点检测
  • 解析json方案

    方案一 方案二 方案三 方案四 方案五 方案六 方案七
  • 51单片机+DHT11温湿度传感器+LCD1602显示(最好用的程序,没有之一)

    DHT11传感器原理很简单 xff08 我就不过多解释了 xff09 xff0c 但使用中可能会遇到很多问题 xff0c 问题的本质大部分出在了延时函数之中 xff0c 传统的软件延时与实际相差太多 xff0c 所以尽量不要用 xff0c
  • 51单片机+温湿度传感器+proteus仿真

    前段时间老师让提交的工程实训作业 xff0c 本来想用51单片机加DHT11做一个温湿度控制系统 xff0c 结果发现DHT11温湿度传感器情况下怎么也不好用 xff0c 从网上找了老多资料 xff0c 还是不行 xff0c 所以果断放弃
  • Linux网络编程项目---网络词典(带源码)

    源代码 xff1a https wwz lanzouq com iPsJ706ghzhc 1 包含的文件 client span class token operator span span class token operator spa
  • 四、stm32-USART串口通讯(重定向、接发通信、控制LED亮灭)

    目录 一 固件库模板二 准备资料三 STM32串口通讯1 STM32的USART 简介2 USART 功能框图2 1 数据寄存器2 2 控制器2 3 发送器2 4 接收器2 5 小数波特率生成 3 校验控制3 1 中断控制 4 USART
  • STM32软件模拟iic驱动oled(显示汉字,图片)(二)

    在上一篇介绍的软件模拟iic及iic源码后 xff0c 今天来实现显示汉字与图片以及各个函数的介绍 一 函数介绍及使用 1 显示字符 OLED ShowStr unsigned char x unsigned char y unsigned
  • CMake笔记--find_package 指定路径

    1 find package 指定路径 1 1 命令 find package span class token punctuation span span class token operator lt span PackageName
  • TM4C123系列(四)————UART串口通信

    一 实验简介 使用TM4C123的串口通信功能实现单片机与PC端通信 二 UART介绍 TM4C123有八个串口 xff0c 其中UART0已经与USB集成 xff0c UART0建议只用来和PC端通信 xff0c 不要与外界通信 除此之外
  • STM32软件模拟iic驱动oled(显示汉字,图片)(一)

    一 iic驱动模式 1 硬件驱动 xff1a 所谓硬件驱动就是使用STM32板子上固定的iic接口 xff0c 但是由于板载iic数量有限 xff0c 且大多和别的外设有引脚复用 xff0c 在别的外设使用的情况下还得通过重映射引到别的引脚
  • 初识ESP8266(二)————搭建网络服务器实现远程控制

    一 实验介绍 8266搭建网络服务器 xff0c 通过同一wifi信号下的终端访问ESP8266IP地址 xff0c 对开发板进行控制 二 代码 1 esp8266 server begin 作用 xff1a 启动网络服务 xff0c 搭建
  • 关于舵机的漂移与不听指挥乱动的问题

    在电赛E题中控制二维云台中出现了两个问题 xff0c 也是好不容易才发现原因然后解决的 一 舵机不听指挥乱动 没有与单片机共地 舵机有三条线 xff0c 分别是正负极和信号线 用来输入PWM信号 xff0c 因为舵机所需要的驱动电压比较大
  • 蓝桥杯嵌入式(STM32F103RBT6)备赛手册(一)

    文章目录 一 基础篇一 点亮LED二 驱动蜂鸣器三 Systick定时器四 定时器五 独立按键 三行代码消抖六 IIC协议七 LCD显示八 串口接收与发送九 ADC采样十 RTC时钟十一 PWM输出及输入捕获 一 基础篇 一 点亮LED 由