文章目录:
一:阵列键盘
1.阵列键盘测试程序
KEYPAD4x4.h
KEYPAD4x4.c
main.c
2.键盘中断测试程序
NVIC.h
NVIC.c
main.c
二:舵机控制
1.延时函数驱动舵机程序
SG90.h
SG90.c
main.c
2.PWM(脉冲宽度调制 脉宽调制/占空比)驱动舵机程序
pwm.h
pwm.c
main.c
三:DHT11芯片(DHT11温湿度显示程序)
dht11.h
dht11.c
main.c
四:MPU6050(六轴加速度和陀螺仪传感器芯片)
MPU6050.h
MPU6050.c
main.c
一:阵列键盘
对跳线进行设置
第一步:把ADC输入的两个跳线断开第二步:将模拟摇杆的三个跳线断开第三步:将触摸按键的四个跳线断开第四步:将旋转编码器的三个跳线断开
1.阵列键盘测试程序
按下时:红线蓝线短接
阵列键盘
新建文件夹
Hardware文件夹——>KEYPAD4x4文件夹——>KEYPAD4x4.c KEYPAD4x4.h
KEYPAD4x4.h
#ifndef __KEYPAD4x4_H #define __KEYPAD4x4_H #include "sys.h" #include "delay.h"#define KEYPAD4x4PORT GPIOA //定义IO接口组 #define KEY1 GPIO_Pin_0 //定义IO接口 #define KEY2 GPIO_Pin_1 //定义IO接口 #define KEY3 GPIO_Pin_2 //定义IO接口 #define KEY4 GPIO_Pin_3 //定义IO接口 #define KEYa GPIO_Pin_4 //定义IO接口 #define KEYb GPIO_Pin_5 //定义IO接口 #define KEYc GPIO_Pin_6 //定义IO接口 #define KEYd GPIO_Pin_7 //定义IO接口void KEYPAD4x4_Init(void);//初始化 void KEYPAD4x4_Init2(void);//初始化2(用于IO工作方式反转) u8 KEYPAD4x4_Read (void);//读阵列键盘#endif
KEYPAD4x4.c
#include "KEYPAD4x4.h"void KEYPAD4x4_Init(void){ //微动开关的接口初始化GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO的初始化枚举结构 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Pin = KEYa | KEYb | KEYc | KEYd; //选择端口号(0~15或all) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //选择IO接口工作方式 //上拉电阻 GPIO_Init(KEYPAD4x4PORT,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = KEY1 | KEY2 | KEY3 | KEY4; //选择端口号(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(KEYPAD4x4PORT,&GPIO_InitStructure);} void KEYPAD4x4_Init2(void){ //微动开关的接口初始化2(用于IO工作方式反转)GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO的初始化枚举结构 GPIO_InitStructure.GPIO_Pin = KEY1 | KEY2 | KEY3 | KEY4; //选择端口号(0~15或all) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //选择IO接口工作方式 //上拉电阻 GPIO_Init(KEYPAD4x4PORT,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = KEYa | KEYb | KEYc | KEYd; //选择端口号(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(KEYPAD4x4PORT,&GPIO_InitStructure);} u8 KEYPAD4x4_Read (void){//键盘处理函数u8 a=0,b=0;//定义变量KEYPAD4x4_Init();//初始化IOGPIO_ResetBits(KEYPAD4x4PORT,KEY1|KEY2|KEY3|KEY4);GPIO_SetBits(KEYPAD4x4PORT,KEYa|KEYb|KEYc|KEYd);if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYa) || //查寻键盘口的值是否变化!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYb) || !GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYc) || !GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYd)){delay_ms (20);//延时20毫秒if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYa) || //查寻键盘口的值是否变化!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYb) || !GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYc) || !GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYd)){a = GPIO_ReadInputData(KEYPAD4x4PORT)&0xff;//键值放入寄存器a}KEYPAD4x4_Init2();//IO工作方式反转GPIO_SetBits(KEYPAD4x4PORT,KEY1|KEY2|KEY3|KEY4);GPIO_ResetBits(KEYPAD4x4PORT,KEYa|KEYb|KEYc|KEYd);b = GPIO_ReadInputData(KEYPAD4x4PORT)&0xff;//将第二次取得值放入寄存器ba = a|b;//将两个数据相或switch(a){//对比数据值case 0xee: b = 16; break;//对比得到的键值给b一个应用数据case 0xed: b = 15; break;case 0xeb: b = 14; break;case 0xe7: b = 13; break;case 0xde: b = 12; break;case 0xdd: b = 11; break;case 0xdb: b = 10; break;case 0xd7: b = 9; break;case 0xbe: b = 8; break;case 0xbd: b = 7; break;case 0xbb: b = 6; break;case 0xb7: b = 5; break;case 0x7e: b = 4; break;case 0x7d: b = 3; break;case 0x7b: b = 2; break;case 0x77: b = 1; break;default: b = 0; break;//键值错误处理}while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY1) || //等待按键放开!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY2) || !GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY3) || !GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY4));delay_ms (20);//延时20毫秒} return (b);//将b作为返回值 }
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h"#include "KEYPAD4x4.h"int main (void){//主程序u8 s;delay_ms(500); //上电时等待其他器件就绪RCC_Configuration(); //系统时钟初始化 RELAY_Init();//继电器初始化I2C_Configuration();//I2C初始化OLED0561_Init(); //OLED初始化OLED_DISPLAY_8x16_BUFFER(0," YoungTalk "); //显示字符串OLED_DISPLAY_8x16_BUFFER(3," KEYPAD4x4 TEST "); //显示字符串KEYPAD4x4_Init();//阵列键盘初始化while(1){s=KEYPAD4x4_Read();//读出按键值//有按键被按下if(s!=0){ //如按键值不是0,也就是说有按键操作,则判断为真//-------------------------"----------------"OLED_DISPLAY_8x16_BUFFER(6," KEY NO. "); //显示字符串OLED_DISPLAY_8x16(6,8*8,s/10+0x30); //显示十位 偏移量OLED_DISPLAY_8x16(6,9*8,s%10+0x30); //显示个位}} }
2.键盘中断测试程序
嵌套:即是在进入一个中断处理程序之后,还能在中断之内再次产生中断NVIC嵌套向量中断控制器cortex-m3支持256个中断,其中包含了16个内核中断,240个外部中断stm32只有84个中断,包括16个内核中断和68个可屏蔽中断stm32f103上只有60个可屏蔽中断优先级的设置(设置值越小,优先级越高)NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级 NVIC_InitStruct.NVIC_IRQChannelSubPriority=2; //子优先级抢占优先级 又称:主优先级在嵌套时,抢占优先级较高的可以在较低的中断内嵌套中断同一抢占优先级不能嵌套,必须前一个中断处理完成才能进入下一个不同抢占优先级下,响应优先级没有意义响应优先级 又称:子优先级/亚优先级/次优先级/副优先级同一抢占优先级的中断同时产生时,响应优先级较高的先处理同一抢占优先级不能嵌套
新建文件夹
Basic文件夹——>nvic文件夹——>NVIC.c NVIC.h
NVIC.h
#ifndef __NVIC_H #define __NVIC_H #include "sys.h"extern u8 INT_MARK; //中断标志位void KEYPAD4x4_INT_INIT (void); //中断初始化函数#endif
NVIC.c
#include "NVIC.h"u8 INT_MARK;//中断标志位void KEYPAD4x4_INT_INIT (void){ //按键中断初始化NVIC_InitTypeDef NVIC_InitStruct; //定义结构体变量EXTI_InitTypeDef EXTI_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //启动GPIO时钟 (需要与复用时钟一同启动) RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE);//配置端口中断需要启用复用时钟//第1个中断 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource4); //定义 GPIO 中断EXTI_InitStruct.EXTI_Line=EXTI_Line4; //定义中断线EXTI_InitStruct.EXTI_LineCmd=ENABLE; //中断使能EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt; //中断模式为 中断EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling; //下降沿触发EXTI_Init(& EXTI_InitStruct);NVIC_InitStruct.NVIC_IRQChannel=EXTI4_IRQn; //中断线 NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //使能中断NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级 2NVIC_InitStruct.NVIC_IRQChannelSubPriority=2; //子优先级 2NVIC_Init(& NVIC_InitStruct);//第2个中断 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource5); //定义 GPIO 中断EXTI_InitStruct.EXTI_Line=EXTI_Line5; //定义中断线EXTI_InitStruct.EXTI_LineCmd=ENABLE; //中断使能EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt; //中断模式为 中断EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling; //下降沿触发EXTI_Init(& EXTI_InitStruct);NVIC_InitStruct.NVIC_IRQChannel=EXTI9_5_IRQn; //中断线NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //使能中断NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级 2NVIC_InitStruct.NVIC_IRQChannelSubPriority=2; //子优先级 2NVIC_Init(& NVIC_InitStruct);//第3个中断 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6); //定义 GPIO 中断EXTI_InitStruct.EXTI_Line=EXTI_Line6; //定义中断线EXTI_InitStruct.EXTI_LineCmd=ENABLE; //中断使能EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt; //中断模式为 中断EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling; //下降沿触发EXTI_Init(& EXTI_InitStruct);NVIC_InitStruct.NVIC_IRQChannel=EXTI9_5_IRQn; //中断线NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //使能中断NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级 2NVIC_InitStruct.NVIC_IRQChannelSubPriority=2; //子优先级 2NVIC_Init(& NVIC_InitStruct);//第4个中断 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource7); //定义 GPIO 中断EXTI_InitStruct.EXTI_Line=EXTI_Line7; //定义中断线EXTI_InitStruct.EXTI_LineCmd=ENABLE; //中断使能EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt; //中断模式为 中断EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling; //下降沿触发EXTI_Init(& EXTI_InitStruct);NVIC_InitStruct.NVIC_IRQChannel=EXTI9_5_IRQn; //中断线NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //使能中断NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2; //抢占优先级 2NVIC_InitStruct.NVIC_IRQChannelSubPriority=2; //子优先级 2NVIC_Init(& NVIC_InitStruct);}void EXTI4_IRQHandler(void){if(EXTI_GetITStatus(EXTI_Line4)!=RESET){//判断某个线上的中断是否发生 INT_MARK=1;//标志位置1,表示有按键中断EXTI_ClearITPendingBit(EXTI_Line4); //清除 LINE 上的中断标志位} } void EXTI9_5_IRQHandler(void){if(EXTI_GetITStatus(EXTI_Line5)!=RESET){//判断某个线上的中断是否发生 INT_MARK=2;//标志位置1,表示有按键中断EXTI_ClearITPendingBit(EXTI_Line5); //清除 LINE 上的中断标志位} if(EXTI_GetITStatus(EXTI_Line6)!=RESET){//判断某个线上的中断是否发生 INT_MARK=3;//标志位置1,表示有按键中断EXTI_ClearITPendingBit(EXTI_Line6); //清除 LINE 上的中断标志位} if(EXTI_GetITStatus(EXTI_Line7)!=RESET){//判断某个线上的中断是否发生 INT_MARK=4;//标志位置1,表示有按键中断EXTI_ClearITPendingBit(EXTI_Line7); //清除 LINE 上的中断标志位} }
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h"#include "KEYPAD4x4.h" #include "NVIC.h"int main (void){//主程序u8 s;delay_ms(500); //上电时等待其他器件就绪RCC_Configuration(); //系统时钟初始化 RELAY_Init();//继电器初始化I2C_Configuration();//I2C初始化OLED0561_Init(); //OLED初始化OLED_DISPLAY_8x16_BUFFER(0," YoungTalk "); //显示字符串OLED_DISPLAY_8x16_BUFFER(3," KEYPAD4x4 TEST "); //显示字符串INT_MARK=0;//标志位清0NVIC_Configuration();//设置中断优先级KEYPAD4x4_Init();//阵列键盘初始化KEYPAD4x4_INT_INIT();//阵列键盘的中断初始化while(1){//其他程序内容if(INT_MARK){ //中断标志位为1表示有按键中断INT_MARK=0;//标志位清0s=KEYPAD4x4_Read();//读出按键值if(s!=0){ //如按键值不是0,也就是说有按键操作,则判断为真//-------------------------"----------------"OLED_DISPLAY_8x16_BUFFER(6," KEY NO. "); //显示字符串OLED_DISPLAY_8x16(6,8*8,s/10+0x30);//OLED_DISPLAY_8x16(6,9*8,s%10+0x30);//}}} }
二:舵机控制
第一步:将舵机连接到开发板上(舵机接口)第二步:将触摸按键的四个跳线帽短接
注意事项1.舵机上如果有负载需要更大的驱动电流2.必须连续不断地向PWM线发出角度波形,直到达到对应角度3.一般情况下,180度舵机的最大角度可达190度,甚至200度4.要按指定型号舵机的波形与角度对应关系做调试,不盲信理论值
新建文件夹
Hardware文件夹——>SG90文件夹——>SG90.c SG90.h
1.延时函数驱动舵机程序
延时函数利用滴答计时器,虽然可以事项该功能,但实际开发中,这种效率很低
SG90.h
#ifndef __SG90_H #define __SG90_H #include "sys.h" #include "delay.h"#define SE_PORT GPIOA //定义IO接口 #define SE_OUT GPIO_Pin_15 //定义IO接口void SG90_Init(void);//SG90舵机初始化 void SG90_angle(u8 a);//舵机角度设置#endif
SG90.c
#include "SG90.h"void SG90_Init(void){ //舵机接口初始化GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Pin = SE_OUT; //选择端口号(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(SE_PORT, &GPIO_InitStructure);GPIO_WriteBit(SE_PORT,SE_OUT,(BitAction)(0)); //接口输出高电平1 }void SG90_angle(u8 a){ //舵机角度控制设置(参数值0~180)对应角度0~180度u8 b=100;//角度校正偏移量GPIO_WriteBit(SE_PORT,SE_OUT,(BitAction)(1)); //接口输出高电平1delay_us(500+a*10+b); //延时GPIO_WriteBit(SE_PORT,SE_OUT,(BitAction)(0)); //接口输出高电平1delay_us(19500-a*10-b); //延时 }
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "SG90.h" #include "touch_key.h"int main (void){//主程序delay_ms(500); //上电时等待其他器件就绪RCC_Configuration(); //系统时钟初始化 RELAY_Init();//继电器初始化I2C_Configuration();//I2C初始化OLED0561_Init(); //OLED初始化OLED_DISPLAY_8x16_BUFFER(0," YoungTalk "); //显示字符串OLED_DISPLAY_8x16_BUFFER(3," SG90 TEST "); //显示字符串TOUCH_KEY_Init();//按键初始化SG90_Init();//SG90舵机初始化SG90_angle(0);//舵机初步为0(最小值)while(1){if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_A)){ //读触摸按键的电平OLED_DISPLAY_8x16_BUFFER(6," Angle 0 "); //显示字符串SG90_angle(0);//舵机初步为0(最小值)}if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_B)){ //读触摸按键的电平OLED_DISPLAY_8x16_BUFFER(6," Angle 45 "); //显示字符串SG90_angle(45);//舵机初步为0(最小值)}if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_C)){ //读触摸按键的电平OLED_DISPLAY_8x16_BUFFER(6," Angle 90 "); //显示字符串SG90_angle(90);//舵机初步为0(最小值)}if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_D)){ //读触摸按键的电平OLED_DISPLAY_8x16_BUFFER(6," Angle 180 "); //显示字符串SG90_angle(180);//舵机初步为0(最小值)}} }
2.PWM(脉冲宽度调制 脉宽调制/占空比)驱动舵机程序
使用定时器产生PWM(定时器是独立工作的) 不管用户是否按键,PWM都会处在工作状态,一直输出脉冲来控制舵机(舵机会有抖动)
PWM:是利用微处理器的数字输出 来对模拟电路进行控制的一种非常有效的技术应用:在从测量、通信到功率控制与变换的许多领域中必须有一个完整周期(高低电平 高电平决定亮度) 改变高低电平的长度比例,从而达到调节亮度的效果PWM的产生:可由STM32中的定时器产生,包括1个高级定时器TIM1和3个普通定时器TIM2、TIM3、TIM4
为了连接定时器的相关输出:在核心版上通过一条导线连接P415和PB0舵机连接:接P415端口定时器的输出:PB0端口
按A键亮度最暗....按D键亮度最亮(使LED显示占空比使亮度发生变化)
新建文件夹
Basic文件夹——>pwm文件夹——>pwm.c pwm.h
pwm.h
#ifndef __PWM_H #define __PWM_H #include "sys.h"void TIM3_PWM_Init(u16 arr,u16 psc);#endif
pwm.c
#include "pwm.h"void TIM3_PWM_Init(u16 arr,u16 psc){ //TIM3 PWM初始化 arr重装载值 psc预分频系数GPIO_InitTypeDef GPIO_InitStrue;TIM_OCInitTypeDef TIM_OCInitStrue;TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrue;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能TIM3和相关GPIO时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOB时钟(LED在PB0引脚)RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能AFIO时钟(定时器3通道3需要重映射到BP5引脚)GPIO_InitStrue.GPIO_Pin=GPIO_Pin_0; // TIM_CH3GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP; // 复用推挽GPIO_InitStrue.GPIO_Speed=GPIO_Speed_50MHz; //设置最大输出速度GPIO_Init(GPIOB,&GPIO_InitStrue); //GPIO端口初始化设置// GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); //映射,重映射只用于64、100、144脚单片机//当没有重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PA6,PA7,PB0,PB1//当部分重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PB4,PB5,PB0,PB1 (GPIO_PartialRemap_TIM3)//当完全重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PC6,PC7,PC8,PC9 (GPIO_FullRemap_TIM3) TIM_TimeBaseInitStrue.TIM_Period=arr; //设置自动重装载值TIM_TimeBaseInitStrue.TIM_Prescaler=psc; //预分频系数TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up; //计数器向上溢出TIM_TimeBaseInitStrue.TIM_ClockDivision=TIM_CKD_DIV1; //时钟的分频因子,起到了一点点的延时作用,一般设为TIM_CKD_DIV1TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStrue); //TIM3初始化设置(设置PWM的周期)TIM_OCInitStrue.TIM_OCMode=TIM_OCMode_PWM1; // PWM模式1:CNT < CCR时输出有效电平TIM_OCInitStrue.TIM_OCPolarity=TIM_OCPolarity_High;// 设置极性-有效电平为:高电平TIM_OCInitStrue.TIM_OutputState=TIM_OutputState_Enable;// 输出使能TIM_OC3Init(TIM3,&TIM_OCInitStrue); //TIM3的通道3 PWM 模式设置TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能预装载寄存器TIM_Cmd(TIM3,ENABLE); //使能TIM3}
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h" #include "SG90.h" #include "touch_key.h"#include "pwm.h"int main (void){//主程序delay_ms(500); //上电时等待其他器件就绪RCC_Configuration(); //系统时钟初始化 RELAY_Init();//继电器初始化I2C_Configuration();//I2C初始化OLED0561_Init(); //OLED初始化OLED_DISPLAY_8x16_BUFFER(0," YoungTalk "); //显示字符串OLED_DISPLAY_8x16_BUFFER(3," SG90 TEST2 "); //显示字符串TOUCH_KEY_Init();//按键初始化TIM3_PWM_Init(59999,23); //设置频率为50Hz,公式为:溢出时间Tout(单位秒)=(arr+1)(psc+1)/Tclk 20MS = (59999+1)*(23+1)/72000000//Tclk为通用定时器的时钟,如果APB1没有分频,则就为系统时钟,72MHZ//PWM时钟频率=72000000/(59999+1)*(23+1) = 50HZ (20ms),设置自动装载值60000,预分频系数24while(1){if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_A)){ //读触摸按键的电平OLED_DISPLAY_8x16_BUFFER(6," Angle 0 "); //显示字符串TIM_SetCompare3(TIM3,1500); //改变比较值TIM3->CCR2达到调节占空比的效果(1500为0度)}if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_B)){ //读触摸按键的电平OLED_DISPLAY_8x16_BUFFER(6," Angle 45 "); //显示字符串TIM_SetCompare3(TIM3,3000); //改变比较值TIM3->CCR2达到调节占空比的效果}if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_C)){ //读触摸按键的电平OLED_DISPLAY_8x16_BUFFER(6," Angle 90 "); //显示字符串TIM_SetCompare3(TIM3,4500); //改变比较值TIM3->CCR2达到调节占空比的效果}if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_D)){ //读触摸按键的电平OLED_DISPLAY_8x16_BUFFER(6," Angle 180 "); //显示字符串TIM_SetCompare3(TIM3,7500); //改变比较值TIM3->CCR2达到调节占空比的效果}} }
三:DHT11芯片(DHT11温湿度显示程序)
温湿度传感器
引脚说明
串行接口
通信过程
每一个波形的事件长度
数字0 1信号表示方法
新建文件夹
Hardware文件夹——>DHT11文件夹——>dht11.c dht11.h
通过程序对波形图的高低电平进行采样判断:有些部分需要输出,有些部分需要输入,通过while循环不断判断高低电平的开始位置,再通过延时函数判断数据位是"1"还是"0"
最终将5个字节数据读取进来进行数据校验,校验好后再放入到对应的变量当中,在主函数当中将读到的温度湿度数据以十进制数的方式进行显示,最终就达到了程序效果
dht11.h
#ifndef __DHT11_H #define __DHT11_H #include "sys.h" #include "delay.h"#define DHT11PORT GPIOA //定义IO接口 #define DHT11_IO GPIO_Pin_15 //定义IO接口void DHT11_IO_OUT (void); void DHT11_IO_IN (void); void DHT11_RST (void); u8 Dht11_Check(void); u8 Dht11_ReadBit(void); u8 Dht11_ReadByte(void); u8 DHT11_Init (void); u8 DHT11_ReadData(u8 *h);#endif
dht11.c
#include "dht11.h"//切换端口的工作状态(因为有输出也有输入) void DHT11_IO_OUT (void){ //端口变为输出GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = DHT11_IO; //选择端口号(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(DHT11PORT, &GPIO_InitStructure); }void DHT11_IO_IN (void){ //端口变为输入GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = DHT11_IO; //选择端口号(0~15或all) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //选择IO接口工作方式 GPIO_Init(DHT11PORT, &GPIO_InitStructure); }void DHT11_RST (void){ //DHT11端口复位,发出起始信号(IO发送)DHT11_IO_OUT();GPIO_ResetBits(DHT11PORT,DHT11_IO); // delay_ms(20); //拉低至少18ms GPIO_SetBits(DHT11PORT,DHT11_IO); // delay_us(30); //主机拉高20~40us }u8 Dht11_Check(void){ //等待DHT11回应,返回1:未检测到DHT11,返回0:成功(IO接收) u8 retry=0;DHT11_IO_IN();//IO到输入状态 while (GPIO_ReadInputDataBit(DHT11PORT,DHT11_IO)&&retry<100){//DHT11会拉低40~80usretry++;delay_us(1);} if(retry>=100)return 1; else retry=0;while (!GPIO_ReadInputDataBit(DHT11PORT,DHT11_IO)&&retry<100){//DHT11拉低后会再次拉高40~80usretry++;delay_us(1);}if(retry>=100)return 1; return 0; }u8 Dht11_ReadBit(void){ //从DHT11读取一个位 返回值:1/0u8 retry=0;while(GPIO_ReadInputDataBit(DHT11PORT,DHT11_IO)&&retry<100){//等待变为低电平retry++;delay_us(1);}retry=0;while(!GPIO_ReadInputDataBit(DHT11PORT,DHT11_IO)&&retry<100){//等待变高电平retry++;delay_us(1);}delay_us(40);//等待40us //用于判断高低电平,即数据1或0if(GPIO_ReadInputDataBit(DHT11PORT,DHT11_IO))return 1; else return 0; }u8 Dht11_ReadByte(void){ //从DHT11读取一个字节 返回值:读到的数据u8 i,dat;dat=0;for (i=0;i<8;i++){ dat<<=1; dat|=Dht11_ReadBit();} return dat; }u8 DHT11_Init (void){ //DHT11初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE, ENABLE); //APB2外设时钟使能 DHT11_RST();//DHT11端口复位,发出起始信号return Dht11_Check(); //等待DHT11回应 }u8 DHT11_ReadData(u8 *h){ //读取一次数据//湿度值(十进制,范围:20%~90%) ,温度值(十进制,范围:0~50°),返回值:0,正常;1,失败 u8 buf[5];u8 i;DHT11_RST();//DHT11端口复位,发出起始信号if(Dht11_Check()==0){ //等待DHT11回应for(i=0;i<5;i++){//读取5位数据buf[i]=Dht11_ReadByte(); //读出数据}if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4]){ //数据校验*h=buf[0]; //将湿度值放入指针1h++;*h=buf[2]; //将温度值放入指针2}}else return 1;return 0; }
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h"#include "dht11.h"int main (void){//主程序u8 b[2];delay_ms(1000); //上电时等待其他器件就绪RCC_Configuration(); //系统时钟初始化 RELAY_Init();//继电器初始化I2C_Configuration();//I2C初始化OLED0561_Init(); //OLED初始化OLED_DISPLAY_8x16_BUFFER(0," YoungTalk "); //显示字符串OLED_DISPLAY_8x16_BUFFER(2," DHT11 TEST "); //显示字符串if(DHT11_Init()==0){ //DHT11初始化 返回0成功,1失败OLED_DISPLAY_8x16_BUFFER(4,"Humidity: % "); //显示字符串OLED_DISPLAY_8x16_BUFFER(6,"Temperature: C"); //显示字符串}else{OLED_DISPLAY_8x16_BUFFER(4,"DHT11INIT ERROR!"); //显示字符串}delay_ms(1000);//DHT11初始化后必要的延时(不得小于1秒)while(1){if(DHT11_ReadData(b)==0){//读出温湿度值 指针1是湿度 20~90%,指针2是温度 0~50C,数据为十进制OLED_DISPLAY_8x16(4,9*8,b[0]/10 +0x30);//显示湿度值OLED_DISPLAY_8x16(4,10*8,b[0]%10 +0x30);//OLED_DISPLAY_8x16(6,12*8,b[1]/10 +0x30);//显示温度值OLED_DISPLAY_8x16(6,13*8,b[1]%10 +0x30);//}else{OLED_DISPLAY_8x16_BUFFER(6,"DHT11READ ERROR!"); //显示字符串}delay_ms(1000); //延时,刷新数据的频率(不得小于1秒)} }
四:MPU6050(六轴加速度和陀螺仪传感器芯片)
可以实现对自身位移和旋转角度的感知
加速度传感器:检测位移
陀螺仪传感器:检测方向和旋转的运动
MPU6050原始数据显示程序
新建文件夹
Hardware文件夹——>MPU6050文件夹——>MPU6050.c MPU6050.h
MPU6050.h
#ifndef __MPU6050_H #define __MPU6050_H #include "sys.h" #include "i2c.h" //i2c总线通信 #include "delay.h"#define MPU6050_ADD 0xD0 //器件地址(AD0悬空或低电平时地址是0xD0,为高电平时为0xD2,7位地址:1101 000x)#define MPU6050_RA_XG_OFFS_TC 0x00 #define MPU6050_RA_YG_OFFS_TC 0x01 #define MPU6050_RA_ZG_OFFS_TC 0x02 #define MPU6050_RA_X_FINE_GAIN 0x03 #define MPU6050_RA_Y_FINE_GAIN 0x04 #define MPU6050_RA_Z_FINE_GAIN 0x05 #define MPU6050_RA_XA_OFFS_H 0x06 #define MPU6050_RA_XA_OFFS_L_TC 0x07 #define MPU6050_RA_YA_OFFS_H 0x08 #define MPU6050_RA_YA_OFFS_L_TC 0x09 #define MPU6050_RA_ZA_OFFS_H 0x0A #define MPU6050_RA_ZA_OFFS_L_TC 0x0B #define MPU6050_RA_XG_OFFS_USRH 0x13 #define MPU6050_RA_XG_OFFS_USRL 0x14 #define MPU6050_RA_YG_OFFS_USRH 0x15 #define MPU6050_RA_YG_OFFS_USRL 0x16 #define MPU6050_RA_ZG_OFFS_USRH 0x17 #define MPU6050_RA_ZG_OFFS_USRL 0x18 #define MPU6050_RA_SMPLRT_DIV 0x19 #define MPU6050_RA_CONFIG 0x1A #define MPU6050_RA_GYRO_CONFIG 0x1B #define MPU6050_RA_ACCEL_CONFIG 0x1C #define MPU6050_RA_FF_THR 0x1D #define MPU6050_RA_FF_DUR 0x1E #define MPU6050_RA_MOT_THR 0x1F #define MPU6050_RA_MOT_DUR 0x20 #define MPU6050_RA_ZRMOT_THR 0x21 #define MPU6050_RA_ZRMOT_DUR 0x22 #define MPU6050_RA_FIFO_EN 0x23 #define MPU6050_RA_I2C_MST_CTRL 0x24 #define MPU6050_RA_I2C_SLV0_ADDR 0x25 #define MPU6050_RA_I2C_SLV0_REG 0x26 #define MPU6050_RA_I2C_SLV0_CTRL 0x27 #define MPU6050_RA_I2C_SLV1_ADDR 0x28 #define MPU6050_RA_I2C_SLV1_REG 0x29 #define MPU6050_RA_I2C_SLV1_CTRL 0x2A #define MPU6050_RA_I2C_SLV2_ADDR 0x2B #define MPU6050_RA_I2C_SLV2_REG 0x2C #define MPU6050_RA_I2C_SLV2_CTRL 0x2D #define MPU6050_RA_I2C_SLV3_ADDR 0x2E #define MPU6050_RA_I2C_SLV3_REG 0x2F #define MPU6050_RA_I2C_SLV3_CTRL 0x30 #define MPU6050_RA_I2C_SLV4_ADDR 0x31 #define MPU6050_RA_I2C_SLV4_REG 0x32 #define MPU6050_RA_I2C_SLV4_DO 0x33 #define MPU6050_RA_I2C_SLV4_CTRL 0x34 #define MPU6050_RA_I2C_SLV4_DI 0x35 #define MPU6050_RA_I2C_MST_STATUS 0x36 #define MPU6050_RA_INT_PIN_CFG 0x37 #define MPU6050_RA_INT_ENABLE 0x38 #define MPU6050_RA_DMP_INT_STATUS 0x39 #define MPU6050_RA_INT_STATUS 0x3A #define MPU6050_RA_ACCEL_XOUT_H 0x3B #define MPU6050_RA_ACCEL_XOUT_L 0x3C #define MPU6050_RA_ACCEL_YOUT_H 0x3D #define MPU6050_RA_ACCEL_YOUT_L 0x3E #define MPU6050_RA_ACCEL_ZOUT_H 0x3F #define MPU6050_RA_ACCEL_ZOUT_L 0x40 #define MPU6050_RA_TEMP_OUT_H 0x41 #define MPU6050_RA_TEMP_OUT_L 0x42 #define MPU6050_RA_GYRO_XOUT_H 0x43 #define MPU6050_RA_GYRO_XOUT_L 0x44 #define MPU6050_RA_GYRO_YOUT_H 0x45 #define MPU6050_RA_GYRO_YOUT_L 0x46 #define MPU6050_RA_GYRO_ZOUT_H 0x47 #define MPU6050_RA_GYRO_ZOUT_L 0x48 #define MPU6050_RA_EXT_SENS_DATA_00 0x49 #define MPU6050_RA_EXT_SENS_DATA_01 0x4A #define MPU6050_RA_EXT_SENS_DATA_02 0x4B #define MPU6050_RA_EXT_SENS_DATA_03 0x4C #define MPU6050_RA_EXT_SENS_DATA_04 0x4D #define MPU6050_RA_EXT_SENS_DATA_05 0x4E #define MPU6050_RA_EXT_SENS_DATA_06 0x4F #define MPU6050_RA_EXT_SENS_DATA_07 0x50 #define MPU6050_RA_EXT_SENS_DATA_08 0x51 #define MPU6050_RA_EXT_SENS_DATA_09 0x52 #define MPU6050_RA_EXT_SENS_DATA_10 0x53 #define MPU6050_RA_EXT_SENS_DATA_11 0x54 #define MPU6050_RA_EXT_SENS_DATA_12 0x55 #define MPU6050_RA_EXT_SENS_DATA_13 0x56 #define MPU6050_RA_EXT_SENS_DATA_14 0x57 #define MPU6050_RA_EXT_SENS_DATA_15 0x58 #define MPU6050_RA_EXT_SENS_DATA_16 0x59 #define MPU6050_RA_EXT_SENS_DATA_17 0x5A #define MPU6050_RA_EXT_SENS_DATA_18 0x5B #define MPU6050_RA_EXT_SENS_DATA_19 0x5C #define MPU6050_RA_EXT_SENS_DATA_20 0x5D #define MPU6050_RA_EXT_SENS_DATA_21 0x5E #define MPU6050_RA_EXT_SENS_DATA_22 0x5F #define MPU6050_RA_EXT_SENS_DATA_23 0x60 #define MPU6050_RA_MOT_DETECT_STATUS 0x61 #define MPU6050_RA_I2C_SLV0_DO 0x63 #define MPU6050_RA_I2C_SLV1_DO 0x64 #define MPU6050_RA_I2C_SLV2_DO 0x65 #define MPU6050_RA_I2C_SLV3_DO 0x66 #define MPU6050_RA_I2C_MST_DELAY_CTRL 0x67 #define MPU6050_RA_SIGNAL_PATH_RESET 0x68 #define MPU6050_RA_MOT_DETECT_CTRL 0x69 #define MPU6050_RA_USER_CTRL 0x6A #define MPU6050_RA_PWR_MGMT_1 0x6B //电源管理专用寄存器 #define MPU6050_RA_PWR_MGMT_2 0x6C #define MPU6050_RA_BANK_SEL 0x6D #define MPU6050_RA_MEM_START_ADDR 0x6E #define MPU6050_RA_MEM_R_W 0x6F #define MPU6050_RA_DMP_CFG_1 0x70 #define MPU6050_RA_DMP_CFG_2 0x71 #define MPU6050_RA_FIFO_COUNTH 0x72 #define MPU6050_RA_FIFO_COUNTL 0x73 #define MPU6050_RA_FIFO_R_W 0x74 #define MPU6050_RA_WHO_AM_I 0x75 /void MPU6050_Init(void); void MPU6050_READ(u16* n); #endif
MPU6050.c
#include "MPU6050.h"void MPU6050_Init(void){ //初始化MPU6050I2C_SAND_BYTE(MPU6050_ADD,MPU6050_RA_PWR_MGMT_1,0x80);//解除休眠状态 最高位的数据为1,从而进入复位状态delay_ms(1000); //等待器件就绪I2C_SAND_BYTE(MPU6050_ADD,MPU6050_RA_PWR_MGMT_1,0x00);//解除休眠状态I2C_SAND_BYTE(MPU6050_ADD,MPU6050_RA_SMPLRT_DIV,0x07);//陀螺仪采样率I2C_SAND_BYTE(MPU6050_ADD,MPU6050_RA_CONFIG,0x06); I2C_SAND_BYTE(MPU6050_ADD,MPU6050_RA_ACCEL_CONFIG,0x00);//配置加速度传感器工作在16G模式I2C_SAND_BYTE(MPU6050_ADD,MPU6050_RA_GYRO_CONFIG,0x18);//陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s) }void MPU6050_READ(u16* n){ //读出X、Y、Z三轴加速度/陀螺仪原始数据 //n[0]是AX,n[1]是AY,n[2]是AZ,n[3]是GX,n[4]是GY,n[5]是GZ u8 i;u8 t[14]; I2C_READ_BUFFER(MPU6050_ADD, MPU6050_RA_ACCEL_XOUT_H, t, 14); //读出连续的数据地址,包括了加速度和陀螺仪共12字节for(i=0; i<3; i++) //整合加速度n[i]=((t[2*i] << 8) + t[2*i+1]);for(i=4; i<7; i++) //整合陀螺仪n[i-1]=((t[2*i] << 8) + t[2*i+1]); }
main.c
#include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "relay.h" #include "oled0561.h"#include "MPU6050.h"int main (void){//主程序u16 t[6]={0};delay_ms(500); //上电时等待其他器件就绪RCC_Configuration(); //系统时钟初始化 RELAY_Init();//继电器初始化I2C_Configuration();//I2C初始化OLED0561_Init(); //OLED初始化OLED_DISPLAY_8x16_BUFFER(0," MPU6050 TEST "); //显示字符串OLED_DISPLAY_8x16_BUFFER(2,"X: X: "); //显示字符串OLED_DISPLAY_8x16_BUFFER(4,"Y: Y: "); //显示字符串OLED_DISPLAY_8x16_BUFFER(6,"Z: Z: "); //显示字符串MPU6050_Init(); //MPU6050初始化while(1){MPU6050_READ(t); //加速度//其中t[0~2]是加速度ACCEL,t[3~5]是陀螺仪GYROOLED_DISPLAY_8x16(2,2*8,t[0]/10000 +0x30);//显示OLED_DISPLAY_8x16(2,3*8,t[0]%10000/1000 +0x30);//显示OLED_DISPLAY_8x16(2,4*8,t[0]%1000/100 +0x30);//OLED_DISPLAY_8x16(2,5*8,t[0]%100/10 +0x30);//OLED_DISPLAY_8x16(2,6*8,t[0]%10 +0x30);//OLED_DISPLAY_8x16(2,11*8,t[3]/10000 +0x30);//显示OLED_DISPLAY_8x16(2,12*8,t[3]%10000/1000 +0x30);//显示OLED_DISPLAY_8x16(2,13*8,t[3]%1000/100 +0x30);//OLED_DISPLAY_8x16(2,14*8,t[3]%100/10 +0x30);//OLED_DISPLAY_8x16(2,15*8,t[3]%10 +0x30);//OLED_DISPLAY_8x16(4,2*8,t[1]/10000 +0x30);//显示OLED_DISPLAY_8x16(4,3*8,t[1]%10000/1000 +0x30);//显示OLED_DISPLAY_8x16(4,4*8,t[1]%1000/100 +0x30);//OLED_DISPLAY_8x16(4,5*8,t[1]%100/10 +0x30);//OLED_DISPLAY_8x16(4,6*8,t[1]%10 +0x30);//OLED_DISPLAY_8x16(4,11*8,t[4]/10000 +0x30);//显示OLED_DISPLAY_8x16(4,12*8,t[4]%10000/1000 +0x30);//显示OLED_DISPLAY_8x16(4,13*8,t[4]%1000/100 +0x30);//OLED_DISPLAY_8x16(4,14*8,t[4]%100/10 +0x30);//OLED_DISPLAY_8x16(4,15*8,t[4]%10 +0x30);//OLED_DISPLAY_8x16(6,2*8,t[2]/10000 +0x30);//显示OLED_DISPLAY_8x16(6,3*8,t[2]%10000/1000 +0x30);//显示OLED_DISPLAY_8x16(6,4*8,t[2]%1000/100 +0x30);//OLED_DISPLAY_8x16(6,5*8,t[2]%100/10 +0x30);//OLED_DISPLAY_8x16(6,6*8,t[2]%10 +0x30);//OLED_DISPLAY_8x16(6,11*8,t[5]/10000 +0x30);//显示OLED_DISPLAY_8x16(6,12*8,t[5]%10000/1000 +0x30);//显示OLED_DISPLAY_8x16(6,13*8,t[5]%1000/100 +0x30);//OLED_DISPLAY_8x16(6,14*8,t[5]%100/10 +0x30);//OLED_DISPLAY_8x16(6,15*8,t[5]%10 +0x30);//delay_ms(200); //延时(决定刷新速度)} }