基本功能各部分代码已完成,待整体进行调试
u8 Array_KEY_Scan(u8 mode) { u8 KeyValue; if(!GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_3)) { LED0 = 0; GPIO_ResetBits(GPIOF,GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); if((GPIOF->IDR&0x00f0)!=0x0000 ) { delay_ms(2); if((GPIOF->IDR&0x00f0)!=0x0000) { switch(GPIOF->IDR&0x00f0) { case 0x0010: KeyValue = '0';break; case 0x0020: KeyValue = 'o';break; case 0x0040: KeyValue = 'r';break; case 0x0080: KeyValue = '*';break; } LED1= 0; while((GPIOF->IDR&0x00f0)!=0x0000); LED0 =1; LED1 = 1; return KeyValue; } } } else if(!GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_2)) { GPIO_ResetBits(GPIOF,GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); if((GPIOF->IDR&0x00f0)!=0x0000 ) { delay_ms(2); if((GPIOF->IDR&0x00f0)!=0x0000) { LED0 = 0; switch(GPIOF->IDR&0x00f0) { case 0x0010: KeyValue = '1';break; case 0x0020: KeyValue = '2';break; case 0x0040: KeyValue = '3';break; case 0x0080: KeyValue = 's';break; } while((GPIOF->IDR&0x00f0)!=0x0000); LED0 = 1; return KeyValue; } } } else if(!GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_1)) { GPIO_ResetBits(GPIOF,GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); if((GPIOF->IDR&0x00f0)!=0x0000 ) { delay_ms(2); if((GPIOF->IDR&0x00f0)!=0x0000) { LED1= 0; switch(GPIOF->IDR&0x00f0) { case 0x0010: KeyValue = '4';break; case 0x0020: KeyValue = '5';break; case 0x0040: KeyValue = '6';break; case 0x0080: KeyValue = '#';break; } while((GPIOF->IDR&0x00f0)!=0x0000); LED1 = 1; return KeyValue; } } } else if(!GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_0)) { GPIO_ResetBits(GPIOF,GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); if((GPIOF->IDR&0x00f0)!=0x0000 ) { delay_ms(2); if((GPIOF->IDR&0x00f0)!=0x0000) { LED1 = 0; LED0 = 0; switch(GPIOF->IDR&0x00f0) { case 0x0010: KeyValue = '7';break; case 0x0020: KeyValue = '8';break; case 0x0040: KeyValue = '9';break; case 0x0080: KeyValue = '*';;break; } while((GPIOF->IDR&0x00f0)!=0x0000); LED0 = 1; LED1 = 1; return KeyValue; } } } return 0; }
#include "motor.h" #include "delay.h" #include "stm32f10x.h" #include "sys.h" #include "stdlib.h" #include "LED.h" void MOTOR_Init() { GPIO_InitTypeDef GPIO_IN; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);//ʹÄÜʱÖÓ£» GPIO_IN.GPIO_Mode = GPIO_Mode_Out_PP;//ÍÆÍìÊä³ö£» GPIO_IN.GPIO_Speed = GPIO_Speed_50MHz; GPIO_IN.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_4|GPIO_Pin_6|GPIO_Pin_8; GPIO_Init(GPIOG,&GPIO_IN); } void SteperFrontTurn(u16 speed) { GPIO_SetBits(GPIOG,GPIO_Pin_2|GPIO_Pin_4); GPIO_ResetBits (GPIOG, GPIO_Pin_6|GPIO_Pin_8); delay_ms(speed); GPIO_SetBits(GPIOG,GPIO_Pin_6|GPIO_Pin_4); GPIO_ResetBits (GPIOG, GPIO_Pin_2|GPIO_Pin_8); delay_ms(speed); GPIO_SetBits(GPIOG,GPIO_Pin_6|GPIO_Pin_8); GPIO_ResetBits (GPIOG, GPIO_Pin_2|GPIO_Pin_4); delay_ms(speed); GPIO_SetBits(GPIOG,GPIO_Pin_2|GPIO_Pin_8); GPIO_ResetBits (GPIOG, GPIO_Pin_4|GPIO_Pin_6); delay_ms(speed); LED0 = 0; } void SteperBackTurn(u16 speed) { GPIO_SetBits(GPIOG,GPIO_Pin_2|GPIO_Pin_4); GPIO_ResetBits (GPIOG, GPIO_Pin_6|GPIO_Pin_8); delay_ms(speed); GPIO_SetBits(GPIOG,GPIO_Pin_2|GPIO_Pin_8); GPIO_ResetBits (GPIOG, GPIO_Pin_4|GPIO_Pin_6); delay_ms(speed); GPIO_SetBits(GPIOG,GPIO_Pin_6|GPIO_Pin_8); GPIO_ResetBits (GPIOG, GPIO_Pin_2|GPIO_Pin_4); delay_ms(speed); GPIO_SetBits(GPIOG,GPIO_Pin_6|GPIO_Pin_4); GPIO_ResetBits (GPIOG, GPIO_Pin_2|GPIO_Pin_8); delay_ms(speed); } void SteperStop() { GPIO_ResetBits(GPIOG,GPIO_Pin_2|GPIO_Pin_4|GPIO_Pin_6|GPIO_Pin_8); } void SteperRun(u16 speed,int angle) { float val,per_round,round =512; int i; per_round = round/360; val = per_round*abs(angle); if(angle>0) { for(i=0;i<val;i++) { SteperFrontTurn(speed); SteperStop(); } } else { for(i=0;i<val;i++) { SteperBackTurn(speed); SteperStop(); } } }
//原子哥的库 //DHT11是单总线传输数据,从mcu发出信号,DHT11响应 //RST:根据数据手册mcu先拉低,延时18ms,再拉高,延时20~40us,发出信号让DHT11发送数据 void DHT11_Rst(void) { DHT11_IO_OUT(); //设置为输出 DHT11_DQ_OUT=0; //输出0,拉低 delay_ms(20); DHT11_DQ_OUT=1; delay_us(30); } //根据开发手册,DHT11在接收正常的时序是拉低信号,之后延时20~40us后拉高,保持40us~50us后发送数据,check()函数是用于检验dht11是否响应 u8 DHT11_Check(void) { u8 retry=0; DHT11_IO_IN(); //进入输入模式,读取dht11信号 while (DHT11_DQ_IN&&retry<100)//读取dht11信号,返回低电平则响应,否则retry++至超时 { retry++; delay_us(1); }; if(retry>=100)return 1; else retry=0; while (!DHT11_DQ_IN&&retry<100)//等待高电平信号,超时未响应 { retry++; delay_us(1); }; if(retry>=100)return 1; return 0; } //读数据,一位一位读 //根据高电平持续时间不同,判断是0还是1 u8 DHT11_Read_Bit(void) { u8 retry=0; while(DHT11_DQ_IN&&retry<100)//读取数据时dht11会先拉低信号 { retry++; delay_us(1); } retry=0; while(!DHT11_DQ_IN&&retry<100)//之后拉高,根据高电平时间判断数据 { retry++; delay_us(1); } delay_us(40); if(DHT11_DQ_IN)return 1;//如果40us后还是高电平,则读取为1 else return 0; } u8 DHT11_Read_Byte(void) //整合数据 { u8 i,dat; dat=0; for (i=0;i<8;i++)//将数据一位一位存入dat { dat<<=1; //左移一位添0 dat|=DHT11_Read_Bit();//读取数据,|按位与,只有都为0才为0 } return dat;//返回读取的数据 } //温湿度数据 //数据由5个字节组成,每个字节8bit,高位先出,依次是湿度的整数、小数,温度的整数、小数。最后一位为校验位,等于温湿度的整数小数之和 u8 DHT11_Read_Data(u8 *temp,u8 *humi) { u8 buf[5];//用于存储五个字节 u8 i; DHT11_Rst();//初始化 if(DHT11_Check()==0)//接收响应 { for(i=0;i<5;i++) { buf[i]=DHT11_Read_Byte(); } if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])//校验 { *humi=buf[0];//最先出的是湿度 *temp=buf[2];//温度 } }else return 1;//返回1无响应 return 0; } // u8 DHT11_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);//使能PG端时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOG, &GPIO_InitStructure); GPIO_SetBits(GPIOG,GPIO_Pin_11); DHT11_Rst(); //初始化,即muc发送激活信号 return DHT11_Check(); }
// 原子哥库 //红外遥控是通过接收脉宽不同的信号识别数据,需要开启输入捕获,用于计算高电平时间,并开启溢出中断,用于判断按键是否松开,以及连发码 void Remote_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_SetBits(GPIOB,GPIO_Pin_9); TIM_TimeBaseStructure.TIM_Period = 10000; TIM_TimeBaseStructure.TIM_Prescaler =(72-1); TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); TIM_ICInitStructure.TIM_Channel = TIM_Channel_4; 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 = 0x03; TIM_ICInit(TIM4, &TIM_ICInitStructure); TIM_Cmd(TIM4,ENABLE ); NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_ITConfig( TIM4,TIM_IT_Update|TIM_IT_CC4,ENABLE);,ÔÊÐíCC4IE²¶»ñÖÐ¶Ï } //RmtSta用于存储遥控器状态 //[7]:最高位,接收到引导码(同步码)标志,接收到同步码,开启数据接收 //[6]: 数据接受完后标记 //[5]:保留 //[4]:上升沿捕获接收标志 //[3:0]:溢出计时器 u8 RmtSta=0; u16 Dval; //存入计数器的值 u32 RmtRec=0;//红外接收到的数据 u8 RmtCnt=0;//按键按下的次数 //定时器4中断服务程序 void TIM4_IRQHandler(void) { if(TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET) { if(RmtSta&0x80) //数据接收标志位,即引导码是否接收到 { RmtSta&=~0X10; //取消上升沿捕获标记 if((RmtSta&0X0F)==0X00)RmtSta|=1<<6; //标记已完成依次按键的键值信息采集(即数据采集已完成) if((RmtSta&0X0F)<14)RmtSta++;//溢出标记,(使用溢出计算连发码时长)连发码多出99.5ms,小于等于130ms代表按键处于连发状态,小于14则计数器增加10ms,rmtsta低四位为计数器溢出存储。 else//由于超过140ms,说明此时已停止按下按键(高电平持续时间) { RmtSta&=~(1<<7); //清空引导标识 RmtSta&=0XF0; //清空计数器 } } } //捕获到上升沿后开始计数,通过上升沿和下降沿的计数差判断高电平时长 if(TIM_GetITStatus(TIM4,TIM_IT_CC4)!=RESET) { if(RDATA)//捕获上升沿 { TIM_OC4PolarityConfig(TIM4,TIM_ICPolarity_Falling);//cc4P=1,设置为下降沿捕获 TIM_SetCounter(TIM4,0); //清空定时器的值,重新计数 RmtSta|=0X10;//标记上升沿被捕获 }else { Dval=TIM_GetCapture4(TIM4); //读取CCR4清CC4IF标记位(即把计数器的值存入Dval) TIM_OC4PolarityConfig(TIM4,TIM_ICPolarity_Rising);//设置为上升沿捕获 if(RmtSta&0X10) //标记高电平捕获完成标志 { if(RmtSta&0X80)//判断是否接受了引导码,没有则要接收,有了则开始接收数据 { //根据高电平时长判断信号 if(Dval>300&&Dval<800) //接收到0 { RmtRec<<=1; RmtRec|=0; }else if(Dval>1400&&Dval<1800) //接收到1 { RmtRec<<=1; . RmtRec|=1; }else if(Dval>2200&&Dval<2600) //接收到连发码 { RmtCnt++; RmtSta&=0XF0; } }else if(Dval>4200&&Dval<4700)//没有接收到引导码,接收引导码 { RmtSta|=1<<7; RmtCnt=0; } } RmtSta&=~(1<<4);//清除上升沿捕获标志 } } TIM_ClearITPendingBit(TIM4,TIM_IT_Update|TIM_IT_CC4);//清除定时器标记 } //处理按键数据 //0为没有按下 //数据由同步码、地址码、地址反码、控制码、控制反码组成,一共5字节 u8 Remote_Scan(void) { u8 sta=0; u8 t1,t2; //(u8 代表8bit) if(RmtSta&(1<<6))//得到一个按键的所有信息了 { t1=RmtRec>>24;//右移24位:得到8bit地址码 t2=(RmtRec>>16)&0xff; //右移16位地址反码 if((t1==(u8)~t2)&&t1==REMOTE_ID)//校验遥控识别码ID及地址(验证地址与地址反码是否相等) { t1=RmtRec>>8;//得到控制码 t2=RmtRec; //控制反码 if(t1==(u8)~t2)sta=t1; //验证 } if((sta==0)||((RmtSta&0X80)==0))//按键数据错误/遥控没有按下 { RmtSta&=~(1<<6);//清除数据接收标记位 RmtCnt=0; //清除计数器的值 } } return sta;//返回数据 }
#include "common.h" #include "stdlib.h" u8 wifi_sta_connect() { atk_8266_send_cmd("AT+CWMODE=1","OK",50); atk_8266_send_cmd("AT+RST","OK",20);//ÖØÆô delay_ms(1000); delay_ms(1000); delay_ms(1000); printf("AT RST success\r\n"); if(atk_8266_send_cmd("AT+CWJAP=wifista_ssid,wifista_password","WIFI GOT IP",300)) { printf("wifi is connecting...\r\n"); delay_ms(1000); delay_ms(1000); } atk_8266_send_cmd("AT+CIPMUX=0","OK",20); printf("end...\r\n"); atk_8266_send_cmd("AT+CIPSTART=\"TCP\",\"192.168.43.1\",8086","OK",200); printf("connect success\r\n"); atk_8266_send_cmd("AT+CIPMODE=1","OK",200); atk_8266_quit_trans(); atk_8266_send_cmd("AT+CIPSEND","OK",20); atk_8266_send_cmd("AT+ATKCLDSTA=\"28278526856927122889\",\"12345678\"","OK",300); printf("end..."); return 0; }
oled 显示图片还在调试中
各部分代码完成,需要合并成完整系统,
目前存在问题:1.按键按下反应不灵敏,导致密码锁没完成
2.返回的温湿度以16进制显示在服务器上。
有待改进部分;引入光敏电阻做成自动窗帘
未完成:空调显示(正在制作)
通过本次暑假考核,我对单片机理解加深了,单片机出了如何使用模块,IO口,最重要的通讯,即与各模块的通讯,与其他单片机的通讯,目前使用到的通讯由:同步异步通信(串口通讯),单总线,spi通讯等。各种通讯方式各有不同,单总线只用一条数据线收发数据,双方要通讯,需要分时间,即一方发送信号告知另一个发送数据。串口通讯由于没有双方没有规定时序,但双方约定波特率,保证通讯。spi通讯由于有了时钟线,双方通讯建立在时钟时序上。再来是数据处理:由于电路只有高电平和低电平两种状态,所以数据本质上二进制数据,一般以字节为单位,即8bit,8bit刚好是无符号char类型数据,8bit也是16进制数。在读取数据一般会使用到位运算。&、|、~,&一般用于判断位,|一般用于存入一位bit,~一用于取反。数据类型、数据存入对于单片机的数据处理是必要技能。单片机的通讯是通过严格数据(既有特定数据用于标记接收和发送、检验等),以及双方规定波特率、时序等完成。最后就算io的操作,通过设置高低电平实现读入写入时序。
PS:目前有些部分不是很清晰