按键分析
按钮抖动:由于按钮使用机械弹簧片切断,按下和松开时会伴随一系列抖动
抖动:使用延迟函数或改进硬件电路
传感器分析
传感器元件主要是可变电阻,比如光敏传感器跟热敏传感器,光线越强或者温度越高,其内部电阻阻值越小,由于不方便直接被观察,所以常常此电阻与定值电阻串联,通过输出电压观察。
滤波器电容器,保持电压输出平稳。一端电路,一端接地。分析电容器可以抹去。N1变小,输出逐渐减少,极限短路,输出VSS;N1变大,极限断路,输出VCC。
下拉:下拉电阻值小。
LM393:电压比较器芯片中有两个操作放大器,即当正相输入大于反相输入时,输出VCC,反之输出VSS。二极化模拟电压可以变成数字电压。
AO:模拟电压输出
DO:数字思压输出
硬件电路分析
对图1,上拉输入,按下时低电平,松开时高电平。如果不设置上拉输入,松开时电平不确定,不正确,必须上拉。stm单片机中有上下拉电阻。对于图3,需要下拉电阻。如果上下拉电阻连接,可以设置浮动模式,因为外部配置,不知道高低电平,如图2和4,当然,图2也可以设置为上拉输入,图4也可以设置为下拉输入,与外部电阻结合,输入信号更稳定,但按键时,电平转换损失更大。
C语言数字类型
char short int longlong
8 16 32 64
char |
8 |
-128~127 |
int8_t |
s8 |
unsignedchar |
8 |
0~255 |
uint8_t |
u8 |
short |
16 |
-32768~32767 |
int16_t |
s16 |
unsignedshort |
16 |
0~65535 |
uint16_t |
u16 |
int |
32 |
-2147483648 ~ 2147483647 |
int32_t |
s32 |
unsigned int |
32 |
0 ~ 4294967295 |
uint32_t |
u32 |
long |
32 |
-2147483648 ~ 2147483647 |
||
unsigned long |
32 |
0 ~ 4294967295 |
||
long long |
64 |
-(2^64)/2 ~ (2^64)/2-1 |
int64_t |
|
unsigned long long |
64 |
0 ~ (2^64)-1 |
uint64_t |
|
float |
32 |
-3.4e38 ~ 3.4e38 |
||
double |
64 |
-1.7e308 ~ 1.7e308 |
宏定义
①#indefine ABC 12345
int a=ABC;相当于a=12345;
把ABC替换12345,其后不需要分号,宏定义把名字简化了,任何都能换
运用宏定义把一个数映射到字符串上,便于理解防止出错,便于快速修改,可以修改一切名字。
比如GPIO口的第十二个引脚,((uint16_t)0x1000)可以用GPIO_Pin_12代替。
②typedef 只能给变量换名字
typedef usigned char uint8_t;
uint8_t a;等效于usigned char a;命名之后两者都可以使用,只不过多了多了一个新名字罢了。
意思: uint8_t 替换usigned char,只能给变化类型改名。
结构体
数组只能组合相同类型的数据,eg:char[20],int[50] 引用:char[0]......
结构体,组合不同类型的数据。struct{char x;int y;float z}structName;
引用,函数名+子项的名字:structName.x=... structName.y=... structName.z=....
结构体成员较多,一半写成:
struct{ char x;
int y;
float z}structName;
运用typedef来替换struct{char x;int y;float z}更加简便
typedef struct{char x;int y;float z} SturctName_t;
SturctName_t c;
SturctName_t d;
以定义GPIO口初始化的函数为例:
大致意思:定义GPIO_InitTypeDef的名称,然后在定义其子项的参数,而后将结构体打包发送到指定位置。
对于上例,还可以写成:pGPIO_InitStructure->'A';pGPIO_InitStructure代表结构体的地址;
因为 GPIO_InitTypeDef GPIO_InitStructure; 已经把 GPIO_InitTypeDef 命名为GPIO_InitStructure;
枚举
定义一个取之受限制的变量,用于限制取值范围,只能写花括号之中的值。
enum{MONDAY=1,TUSDAY,WENSDAY} week;
不赋值证明是按顺序,123456789这样子。
tepedef enum{MONDAY=1,TUSDAY,WENSDAY} Week_t;
引用枚举成员,名=里面的等号左边,也可以被其他引用,比如int a;a=MONDAY;
Week_t week;
week=MONDAY;//week=1;
只能赋值枚举中的值;
eg: typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
FunctionalState a; a=(FunctionalState)1;
a=(FunctionalState)0;
a=ENABLE; a=DISABLE;
按键控制LED
开关使用的时候记得先测试他是那种导通方式,避免踩雷。
正常情况下:若是单刀双掷开关,如下:
分为公共端,常用闭合端和常开端
模块化编程
工程目录建立一个新的文件夹名为HardWare
三个箱子,工程管理新建文件也叫Hareware,可以移动位置
魔术棒。C/C++,添加到头文件列表中
右键Hardware,添加新文件,.c主题代码,.h可对外使用的声明,更改路径
.c初始化:
插入头文件,注意,在书写代码之后,在其最后一行也要以空行结尾,不然报错。
#include "stm32f10x.h"
.h初始化:
#ifndef __LED_H
#define __LED_H
#endif
注意最后同样以空行结尾
打开.c文件,初始化LED端口(也就是打开时钟,配置端口模式,前面配置GPIO口的前两步)
#include "stm32f10x.h" // Device header
void LED_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_1 ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
然后把复制函数第一行放在.h文件中,对外部声明
在主函数中,头文件写上hardware文件中的.h文件夹名字。
在主函数中,若果需要引用的话,就把第一行函数写到哪里。可以写void也可以不写,只要是前后一致即可,如:
void LED_OFF(void);
LED_OFF;
有警告编译一下更新函数;
.c文件中,接着模块化,开启关闭led灯。
#include "stm32f10x.h" // Device header
void LED_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_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
);
}
void LED1_ON(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
void LED1_OFF(void)
{
GPIO_SetBits(GPIOA, GPIO_Pin_1);
}
按键配置
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //读取输入寄存器某一位的值
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx); //读取整个输入寄存器的值
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //读取输出寄存器的值
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx); //读取整个输出寄存器的值
uint8_t Key_GetNum(void) //此函数与主函数中的KeyNum= Key_GetNum();配合,使主函数获得返回键码
{
uint8_t KeyNum = 0;
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0) //如果案件PB1按下变为低电平,进入后续
{
Delay_ms(20); //消抖
while (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0); //如果按键按下一直不动,不改变,死循环
Delay_ms(20); //消抖
KeyNum = 1; //赋值,与按键没按下的值不一样,方便调用
}
return KeyNum; //返回键码
}
主要流程与LED一样。
#include "Delay.h"
#include "LED.h"
#include "Key.h"
uint8_t KeyNum; //在函数里面的是局部变量,只有函数内部自己可以使用,在main函数外面的是全局变量,都可以使用。函数内部优先局部变量。
int main(void)
{
LED_Init();
Key_Init();
while (1)
{
KeyNum = Key_GetNum(); //获取键码
if (KeyNum == 1)
{
LED1_Turn();
}
if (KeyNum == 2)
{
LED2_Turn();
}
}
}
KeyNum的值返回给Key_GetNum();可以直接在主函数中使用,如下例,也可以自主命名,然后赋值,如上例。
光敏传感器(LightSensor)。松手灯亮低电平,电位器调整阈值。蜂鸣器(buzzer)
uint8_t LightSensor_Get(void) //自定义函数名
{
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1); //返回值返回到LightSensor_Get();
}