1. 实现的功能
1. 下位机(stm32) (keil 5 )
1. 按键key1 中断控制 LED 3 的亮灭
2. 按键key2 中断控制 温湿度的获取, (数据通过串口发送给 上位机)
3. 智能检测温湿度是否超标, (超标 开启警报, 开启风扇)
4.OLED 显示 温湿度,(每次获取温湿度,更新数据)
5. 设置窗口看门狗, 保证程序不会出现异常, (中断喂狗)
2. 上位机
1. 按钮1 通过串口通信控制 LED 3 的亮灭
2. 按钮2 通过串口通信控制 蜂鸣器的开启与关闭
3. 按键3 通过 串口通信 获取温湿度的数据
4. 旋钮,通过 串口通信 调节 呼吸灯LED1 的亮度 (PWM 技术控制)
2. 制作过程中遇到的问题
1. 串口通信的时候 下位机接收的 问题 ( 接收函数,判定数据正确的条件有一个 语句后面需要加 \r\n ) 之前的串口调试工具是自动加的, 所以我这里出现了问题。
2. Dht11 温湿度传感器 的时序图的 解读有一点问题, 我之前以为获取数据是只要发送一次起始信号就可以无限获取数据, 但是程序的实验结果告诉我们, 发送一次起始数据, 判断一次 传感器的高低电平数据, 才可以接收一次数据, 而且我们的传感器启动的时候,需要停止 1秒 启动。
3. PWM 控制呼吸灯的时候,发现有程序控制的 LED 3 (比如说是中断), 不可以使用 PWM 的函数控制。 PWM 控制的LED 在主程序里面不可以被控制, 只能通过 PWM 的控制函数控制。
4. 在智能检测温湿度是否超标 的时候需要加一个特判 , 才能防止 超标代码对其他功能的妨碍.
5. OLED 的取模是一个 技术活。!!
6.每一个 程序的功能需要 单独测试 , 封装成函数更好!!
3.代码: (板子不同,硬件的引脚可能不同,程序功能不同)
(板子 stm32 f407VET6 )
下位机: (自己写的 片上外设的控制 文件) (系统的文件自己找, ) (资源已经上传, 0积分 ))
main.cpp
#include "BEEP.h"//蜂鸣器
#include "KEY.h"//按键
#include "LED.h"//LED
#include "motor.h"// 电风扇
#include "delay.h"//延时函数
#include "myiic.h"//IIC
#include "oled.h"//oled 屏幕显示
#include "MyDht11.h"// 温湿度传感器
#include "myusart.h"//串口通信
#include "stdio.h"
#include "PWM.h"//PWM 控制是灯光的亮度
#include "wwdg.h"
#include "misc.h"
#include "stm32f4xx_exti.h"
#include "MYEXIT.h"
void oled_dht11_display(void);//把温度显示在oled上面
void oled_display_x_y(int a,int b,char ff);//oled 屏幕字符显示
void led_twinkle(void);// 第二个灯的闪烁
void wanning_open(void);// 打开警报
void wanning_close(void);//关闭警报
//全局变量
char a111,a222; //a111 湿度, a222 温度
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
ledinit();//LED 灯初始化
key_init();//按键初始化
beepinit();//蜂鸣器初始化0p
motor_init();// 电机初始化
delay_init(168);//延时初始化
IIC_Init();//IIC 初始化
InitOLed();//oled 初始化
myusart_init(115200);// 串口通信初始化
DHT11_init();//温湿度传感器初始化
TIM14_PWM_Init(); //呼吸灯初始化
wwdginit();//窗口看门狗 初始化
MYEXIT_init();//中断初始化
int len;
int panduan=0;
while(1)
{
if(a222>26)
{
wanning_open();
panduan=1;
}
else
{
if(panduan==1)
{
wanning_close();
panduan=0;
}
}
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
if(len <=3)
{
int a1=(int)(USART_RX_BUF[0] -48);
if(a1==1)//开灯
{
select_led(3);
}
if(a1==2)//关灯
{
close_num_led(3);
}
if(a1==3)//开蜂鸣器
{
openBeep();//打开蜂鸣器警报
}
if(a1==4)//关闭蜂鸣器
{
closeBeep();//关闭蜂鸣器
}
if(a1==5)
{
oled_dht11_display();
led_twinkle();
}
if(a1==0)
{
if(len<=3)
{
int a2=(int)(USART_RX_BUF[1] -48)*10;
int a3=(int)(USART_RX_BUF[2] -48);
int a4=a2+a3;
ppp(a4);
}
}
}
USART_RX_STA=0;
}
}
}
void wanning_open()
{
openBeep();//打开蜂鸣器警报
motor_ON();//打开 风扇电机
}
void wanning_close()
{
closeBeep();//关闭蜂鸣器
motor_OFF();//关闭 风扇电机
}
void oled_display_x_y(int a,int b,char ff)
{
char nn = ff/10;
char mm = ff%10;
if(nn==0)
{
OLed_ShowASCII(a,b,"0"); //显示英文。
}
else if(nn==1)
{
OLed_ShowASCII(a,b,"1"); //显示英文。
}
else if(nn==2)
{
OLed_ShowASCII(a,b,"2"); //显示英文。
}
else if(nn==3)
{
OLed_ShowASCII(a,b,"3"); //显示英文。
}
else if(nn==4)
{
OLed_ShowASCII(a,b,"4"); //显示英文。
}
else if(nn==5)
{
OLed_ShowASCII(a,b,"5"); //显示英文。
}
else if(nn==6)
{
OLed_ShowASCII(a,b,"6"); //显示英文。
}
else if(nn==7)
{
OLed_ShowASCII(a,b,"7"); //显示英文。
}
else if(nn==8)
{
OLed_ShowASCII(a,b,"8"); //显示英文。
}
else if(nn==9)
{
OLed_ShowASCII(a,b,"9"); //显示英文。
}
if(mm==0)
{
OLed_ShowASCII(a+8,b,"0"); //显示英文。
}
else if(mm==1)
{
OLed_ShowASCII(a+8,b,"1"); //显示英文。
}
else if(mm==2)
{
OLed_ShowASCII(a+8,b,"2"); //显示英文。
}
else if(mm==3)
{
OLed_ShowASCII(a+8,b,"3"); //显示英文。
}
else if(mm==4)
{
OLed_ShowASCII(a+8,b,"4"); //显示英文。
}
else if(mm==5)
{
OLed_ShowASCII(a+8,b,"5"); //显示英文。
}
else if(mm==6)
{
OLed_ShowASCII(a+8,b,"6"); //显示英文。
}
else if(mm==7)
{
OLed_ShowASCII(a+8,b,"7"); //显示英文。
}
else if(mm==8)
{
OLed_ShowASCII(a+8,b,"8"); //显示英文。
}
else if(mm==9)
{
OLed_ShowASCII(a+8,b,"9"); //显示英文。
}
}
void oled_dht11_display()//把温度显示在oled上面
{
OLed_ShowChina(0,0,HZ4);
OLed_ShowChina(16,0,HZ5);
OLed_ShowChina(32,0,HZ6);
OLed_ShowChina(48,0,HZ7);
OLed_ShowChina(64,0,HZ8);
OLed_ShowChina(80,0,HZ9);
OLed_ShowChina(96,0,HZ10);
OLed_ShowChina(112,0,HZ11);
if(DHT11_ReadData(&a111,&a222)==0)
{
delay_ms(1000);
//printt("oled ",a111);
printt("oled ",a222);
}
OLed_ShowChina(0,2,HZ1);
OLed_ShowChina(16,2,HZ2);
oled_display_x_y(48,2,a222);
OLed_ShowChina(64,2,HZ2);
//第2行显示湿度
OLed_ShowChina(0,4,HZ3);
OLed_ShowChina(16,4,HZ2);
oled_display_x_y(48,4,a111);
OLed_ShowASCII(64,4,"%");
}
void led_twinkle(void)//第二个灯的闪烁
{
int i;
int k=0;
if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_9)==1) // 记录现在的状态
{
k=1;
}
else
{
k=2;
}
//闪烁
for(i=0;i<5;i++)
{
select_led(2);
delay_ms(100);
close_num_led(2);
delay_ms(100);
}
//还原原来的状态
if(k==1)
{
close_num_led(2);
}
else if(k==2)
{
select_led(2);
}
}
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line5) != RESET)//按下KEY2
{
oled_dht11_display();
led_twinkle();
EXTI_ClearITPendingBit(EXTI_Line5);
}
//else if(EXTI_GetITStatus(EXTI_Line6) != RESET) //按下KEY3
//{
// EXTI_ClearITPendingBit(EXTI_Line6);
//}
}
1. BEEP .h
#ifndef __BEEP_H__
#define __BEEP_H__
void beepinit(void);//初始化
void openBeep(void);//打开蜂鸣器
void closeBeep(void);//关闭蜂鸣器
#endif
2.BEEP.c
#include "stm32f4xx.h" //头文件
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "beep.h"
void beepinit(void)
{
//1.时钟问题解决
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);//
//2.引脚配置问题解决
GPIO_InitTypeDef beepstruct;//设置变量
beepstruct.GPIO_Mode= GPIO_Mode_OUT;//输出模式 //引脚输出信号
beepstruct.GPIO_OType=GPIO_OType_PP;//外部无上拉电阻选择推挽输出, 外部有上拉电阻选择开漏输出
beepstruct.GPIO_Pin=GPIO_Pin_10;//引脚的编号是哪个
beepstruct.GPIO_PuPd=GPIO_PuPd_UP; //上拉电阻
beepstruct.GPIO_Speed=GPIO_Low_Speed;//配置速度
GPIO_Init(GPIOB,&beepstruct);
//3.初始化
GPIO_ResetBits(GPIOB,GPIO_Pin_10);//设置输出低电平 ,开始的时候让他不响
}
void openBeep(void)//打开蜂鸣器
{
//GPIO_WriteBit(GPIOB,GPIO_Pin_10,Bit_SET);//打开蜂鸣器
GPIO_SetBits(GPIOB,GPIO_Pin_10);//打开蜂鸣器
}
void closeBeep(void)//关闭蜂鸣器
{
//GPIO_WriteBit(GPIOB,GPIO_Pin_10,Bit_RESET);//关闭蜂鸣器
GPIO_ResetBits(GPIOB,GPIO_Pin_10);//设置输出低电平 ,开始的时候让他不响
}
3.KEY.h
#ifndef __KEY_H__
#define __KEY_H__
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
void key_init(void);//初始化key
int key_youxi(void);//key 按键的游戏
#endif
4.KEY.c
#include "stm32f4xx.h" //头文件
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "key.h"
void key_init(void)//初始化key
{
//初始key1 key2 key3
//1.时钟问题解决
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
GPIO_InitTypeDef keystruct;//设置变量
keystruct.GPIO_Mode=GPIO_Mode_IN; //输入模式 //引脚输入信号
keystruct.GPIO_Pin=GPIO_Pin_4 |GPIO_Pin_5 |GPIO_Pin_6;// 三个按键一起初始化
//keystruct.GPIO_OType 输出类型不需要
keystruct.GPIO_PuPd=GPIO_PuPd_UP;//需要上拉电阻
keystruct.GPIO_Speed=GPIO_Low_Speed;//速度
GPIO_Init(GPIOE,&keystruct);
//初始化
GPIO_SetBits(GPIOE,GPIO_Pin_4|GPIO_Pin_5 |GPIO_Pin_6);//给这些按键高电平 key1 key2 key3
//初始化 key4
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
GPIO_InitTypeDef keystruct1;//设置变量
keystruct1.GPIO_Mode=GPIO_Mode_IN; //输入模式 //引脚输入信号
keystruct1.GPIO_Pin=GPIO_Pin_13;// 按键一起初始化
//keystruct.GPIO_OType 输出类型不需要
keystruct1.GPIO_PuPd=GPIO_PuPd_UP;//需要上拉电阻
keystruct1.GPIO_Speed=GPIO_Low_Speed;//速度
GPIO_Init(GPIOC,&keystruct1);
GPIO_SetBits(GPIOC,GPIO_Pin_13);//给这些按键高电平 key4
}
int key_youxi(void)//key 按键的游戏
{
int i;
if(!GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4))//这个函数是高电平返回 1 低电平 返回 0
{
for(i=10000;i>0;i--);//消抖
if(!GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4))
{
while(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)==0);
return 1;
}
}
if(!GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_5))//这个函数是高电平返回 1 低电平 返回 0
{
for(i=10000;i>0;i--);//消抖
if(!GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_5))
{
while(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_5)==0);
return 2;
}
}
if(!GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_6))//这个函数是高电平返回 1 低电平 返回 0
{
for(i=10000;i>0;i--);//消抖
if(!GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_6))
{
while(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_6)==0);
return 3;
}
}
if(!GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13))//这个函数是高电平返回 1 低电平 返回 0
{
for(i=10000;i>0;i--);//消抖
if(!GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13))
{
while(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13)==0);
return 4;
}
}
return 0;
}
5. LED.h
#ifndef __LED_H__
#define __LED_H__
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
void delay(void);// for 延时
void ledinit(void);//初始化
void select_led(int a);//假如a != 1 2 3 ,就关闭所有的灯
void liushui_led(void);// 展示流水灯的程序
void close_led(void );//关闭所有的小灯
void close_num_led(int a);//关闭指定的小灯
#endif
6. LED.c
#include "stm32f4xx.h" //头文件
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "led.h"
void delay()//延时函数
{
int b=5000000;
while(b--)//形成延时函数
{
}
}
void ledinit()
{
//led 低电平驱动
//3 个led 可控制,一个不可控制
//二极管单向导通,阳极固定高电平,阴极输出高电平,led 灭
//二极管单向导通,阳极固定高电平,阴极输出低电平,led 亮
GPIO_InitTypeDef GIOSTRUCT;
//1.配置时钟: 给个心跳。 选择需要的时钟频率
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
//2.配置功能: 功能太多。 选择GPIO功能;
GIOSTRUCT.GPIO_Mode=GPIO_Mode_OUT ; //输出模式 //引脚输出信号
GIOSTRUCT.GPIO_Pin=GPIO_Pin_8 |GPIO_Pin_9 |GPIO_Pin_10;//led 灯的引脚
GIOSTRUCT.GPIO_PuPd=GPIO_PuPd_UP; //上拉电阻
GIOSTRUCT.GPIO_Speed=GPIO_Low_Speed;//配置速度
//外部无上拉电阻选择推挽输出, 外部有上拉电阻选择开漏输出
GIOSTRUCT.GPIO_OType=GPIO_OType_PP;
GPIO_Init(GPIOE,&GIOSTRUCT);
//GPIO_Init(GPIOE,&GIOSTRUCT);
//3.操作引脚: 输出低电平 led 亮, 输出高电平 led灭
//初始化
GPIO_SetBits(GPIOE,GPIO_Pin_8 |GPIO_Pin_9 |GPIO_Pin_10 );//把灯都关了
//GPIO_ResetBits 输出低电平
//GPIO_SetBits 输出高电平
}
void select_led(int a)//假如a != 1 2 3 ,就关闭所有的灯
{
if(a==1)
{
GPIO_ResetBits(GPIOE,GPIO_Pin_8);//串口组, 引脚//打开第一个灯
}
if(a==2)
{
GPIO_ResetBits(GPIOE,GPIO_Pin_9);//串口组, 引脚//打开第二个灯
}
if(a==3)
{
GPIO_ResetBits(GPIOE,GPIO_Pin_10);//串口组, 引脚//打开第三个灯
}
}
void close_num_led(int a)//关闭指定的小灯
{
if(a==1)
{
GPIO_SetBits(GPIOE,GPIO_Pin_8 );//把灯都关了
}
if(a==2)
{
GPIO_SetBits(GPIOE,GPIO_Pin_9);//把灯都关了
}
if(a==3)
{
GPIO_SetBits(GPIOE,GPIO_Pin_10 );//把灯都关了
}
}
void close_led(void )//关闭所有的小灯
{
GPIO_SetBits(GPIOE,GPIO_Pin_8 |GPIO_Pin_9 |GPIO_Pin_10 );//把灯都关了
}
void liushui_led()//流水灯 , 功能: 从第一个灯 轮流闪烁 一直到最后一个灯,最后把所有的灯关闭。
{
GPIO_SetBits(GPIOE,GPIO_Pin_8 |GPIO_Pin_9 |GPIO_Pin_10 );//把灯都关了
GPIO_ResetBits(GPIOE,GPIO_Pin_8);//串口组, 引脚//打开第一个灯
delay();
GPIO_SetBits(GPIOE,GPIO_Pin_8 |GPIO_Pin_9 |GPIO_Pin_10 );//把灯都关了
GPIO_ResetBits(GPIOE,GPIO_Pin_9);//串口组, 引脚//打开第二个灯
delay();
GPIO_SetBits(GPIOE,GPIO_Pin_8 |GPIO_Pin_9 |GPIO_Pin_10 );//把灯都关了
GPIO_ResetBits(GPIOE,GPIO_Pin_10);//串口组, 引脚//打开第三个灯
delay();
GPIO_SetBits(GPIOE,GPIO_Pin_8 |GPIO_Pin_9 |GPIO_Pin_10 );//把灯都关了
}
7. motor.h
#ifndef __MOTOR_H__
#define __MOTOR_H__
void motor_init(void);//风扇初始化
#define motor_ON() GPIO_SetBits(GPIOB,GPIO_Pin_15);//给e组的8个引脚低电平
#define motor_OFF() GPIO_ResetBits(GPIOB,GPIO_Pin_15);//给e组的8个引脚低电平
// 请按下按键2 让第三个灯亮和灭
#endif
8.motor.c
#include "motor.h"
#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
void motor_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct ;
//第一步:AHB1总线上的E组引脚时钟使能;(心脏开始跳动)
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
//设置gpio结构体
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15 ; //控制哪一个引脚 PE8
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; // 设置引脚为输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //设置输出速度
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽方式
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; //设置高电平还是低电平
//设置GPIO口寄存器数据
GPIO_Init(GPIOB,&GPIO_InitStruct);
GPIO_ResetBits(GPIOB,GPIO_Pin_15);//关闭电机
}
9. MyDht11.h
#ifndef __MYDHT11_H__
#define __MYDHT11_H__
#include "stm32f4xx.h"
void DHT11_init(void); //初始化
void DHT11_InMode(void); //模式变为 输入模式
void DHT11_OutMode(void);// 模式变为 输出模式
unsigned char DHT11_Read_Bit(void);//获取一位的 u8 数据
unsigned char DHT11_ReadData(char * humi,char *temp);//获取 5 个u8 数据, 进行校验和
void dht11_play_data(void);//输出数据
#endif
10. MyDht11.c
#include "MyDht11.h"
#include "stm32f4xx.h"
#include "delay.h"
#include "myusart.h"
char buff[5] = "";
char humi = 0 ,temp = 0 ;
char flg = 100 ,flg1 = 100;
//读出来的数据是16进制也没事。把二进制发送上位机也没事。只要是一个字节就行。
//引脚:PA3
void DHT11_init()
{
//1,配置时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
//2.配置引脚
GPIO_InitTypeDef DHT11struct;
//填写引脚
DHT11struct.GPIO_Pin = GPIO_Pin_3;
//填写速度
DHT11struct.GPIO_Speed = GPIO_Speed_2MHz;
DHT11struct.GPIO_PuPd = GPIO_PuPd_NOPULL ;
//填写电阻
DHT11struct.GPIO_Mode = GPIO_Mode_OUT;
//即可以输出高电平也可以输出低电平
DHT11struct.GPIO_OType = GPIO_OType_OD;
GPIO_Init(GPIOA,&DHT11struct);
//把引脚拉高。
GPIO_SetBits(GPIOA,GPIO_Pin_3);
}
//输入模式函数
void DHT11_InMode()
{
//配置引脚
GPIO_InitTypeDef DHT11struct;
//填写引脚
DHT11struct.GPIO_Pin = GPIO_Pin_3;
//填写速度
DHT11struct.GPIO_Speed = GPIO_Speed_2MHz;
//填写电阻
DHT11struct.GPIO_Mode = GPIO_Mode_IN;
DHT11struct.GPIO_PuPd = GPIO_PuPd_NOPULL ;
//即可以输出高电平也可以输出低电平
GPIO_Init(GPIOA,&DHT11struct);
}
//输入模式函数
void DHT11_OutMode()
{
//配置引脚
GPIO_InitTypeDef DHT11struct;
//填写引脚
DHT11struct.GPIO_Pin = GPIO_Pin_3;
//填写速度
DHT11struct.GPIO_Speed = GPIO_Speed_2MHz;
//填写电阻
//即可以输出高电平也可以输出低电平
DHT11struct.GPIO_OType = GPIO_OType_OD;
DHT11struct.GPIO_Mode = GPIO_Mode_OUT;
DHT11struct.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOA,&DHT11struct);
GPIO_SetBits(GPIOA,GPIO_Pin_3);
}
unsigned char DHT11_Read_Bit()
{
unsigned char readbit = 0 ;
unsigned int i = 0 ;
for(i = 0 ; i < 8 ; i++)
{
//为了避免最高位被移出去。
readbit = readbit << 1 ;
//1在内部也要等待高电平结束。因为在循环过程中,有高电平的持续时间。
//高电平是上一个周期的数据
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3));
//2等待引脚变为高电平,如果是低电平就卡主,等低电平结束
while(!GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3));
//如果是高电平持续30us
//这里是读位数据。
//如果高电平持续时间较长,也就是30us之后还是高电平
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3))
{
//如果读到的是高电平并且 50us以后又读一次还是高电平。
delay_us(30);
}
//又读一次还是高电平,那么久写数据1,否则就是低电平。
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3))
readbit |= 1 ;
else
readbit |= 0 ;
}
return readbit;
}
unsigned char DHT11_ReadData(char * humi,char *temp)
{
unsigned char num = 0 ;
unsigned int i = 0 ;
//1.主机发送开始信号20ms,低电平20ms。至少拉低。
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
delay_ms(20);
//2.主机拉高30us
GPIO_SetBits(GPIOA,GPIO_Pin_3);
delay_us(30);
DHT11_InMode();
//如果发过来的是高电平,就等待高电平结束。
//因为外拉电阻,如果读到的是高电平,就等待高电平结束。
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3));
//3如果读到的是低电平,那么就等待低电平结束。
while(!GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3))
{
//响应信号
flg = 0xee ;
}
//4等待高电平结束。高点平持续时间太久也不行。
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3))
{ //如果低电平持续的时间太长,那么也要退出。
delay_us(4);
num++;
if(num > 20)
return 1;
}
//高电平一旦结束,那么就是信号来了。
//开始读数据
// buff[0] = DHT11_Read_Bit();
// buff[1] = DHT11_Read_Bit();
// buff[2] = DHT11_Read_Bit();
// buff[3] = DHT11_Read_Bit();
// buff[4] = DHT11_Read_Bit();
for(i = 0 ; i < 5 ; i++)
{
//读五次数据,五个字节。
buff[i] = DHT11_Read_Bit();
}
//函数结束以后要把引脚调整为输出模式
DHT11_OutMode();
//5.校验数据
if(buff[4] == buff[0] + buff[1] + buff[2] + buff[3] )
{
*humi = buff[0];
*temp = buff[2] ;
i = 0 ;
return 0;
}
else
return 1 ;
}
void dht11_play_data(void)
{
char a1,a2;
if(DHT11_ReadData(&a1,&a2)==0)
{
delay_ms(1000);
printt("湿度是:",a1);
printt("温度是:",a2);
}
}
11.MYEXIT.h
#ifndef __MYEXIT_H__
#define __MYEXIT_H__
void MYEXIT_init(void);//初始化
#endif
12.MYEXIT.c
#include "MYEXIT.h"
#include "stm32f4xx.h" //头文件
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "KEY.h"
#include "LED.h"
#include "delay.h"
#include "MyDht11.h"
void MYEXIT_init(void)//初始化
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);//中断使能
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource4);//绑定端口
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource5);//绑定端口
EXTI_InitStructure.EXTI_Line = EXTI_Line5 | EXTI_Line4 ;//那根中断线
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//设置中断和事件
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //中断使能
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStruct.NVIC_IRQChannel = EXTI4_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =1;//设置抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority =1; //设置响应优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能
NVIC_Init(&NVIC_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =1;//设置抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority =0; //设置响应优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能
NVIC_Init(&NVIC_InitStruct);
}
void EXTI4_IRQHandler(void)
{
static int LED=1;
delay_ms(20);
if(key_youxi()==1)
{
if(LED%2==1)
{
select_led(3);
LED=0;
}
else if(LED%2==0)
{
close_num_led(3);
LED=1;
}
}
EXTI_ClearITPendingBit(EXTI_Line4);
}
13.myiic.h
#ifndef __MY_I2C_H__
#define __MY_I2C_H__
#include "stm32f4xx.h"
#define SCL_HIGH() GPIO_SetBits(GPIOB,GPIO_Pin_6) //不能有空格,以免宏展开错误
#define SCL_LOW() GPIO_ResetBits(GPIOB,GPIO_Pin_6)
#define SDA_HIGH() GPIO_SetBits(GPIOB,GPIO_Pin_7)
#define SDA_LOW() GPIO_ResetBits(GPIOB,GPIO_Pin_7)
u8 IIC_Read_Byte(unsigned char ack);
void IIC_Send_Byte(u8 txd);
void IIC_NAck(void);
void IIC_Ack(void);
u8 IIC_Wait_Ack(void);
void IIC_Stop(void);
void IIC_Start(void);
void IIC_Init(void);
u8 READ_SDA(void);
void SDA_OUT(void);
void SDA_IN(void);
#endif
14. myiic.c
#include "myiic.h"
#include "delay.h"
#define I2C_DELAY 8
void SDA_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
void SDA_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
/*
//初始化IIC
I2C_SCL ---> PB6
I2C_SDA ---> PB7
*/
//1.初始化函数
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
//GPIOB6,B7初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
//B组第6个引脚高电平 空闲状态
//SCL_HIGH();
SCL_HIGH();
//B组第7个引脚高电平
//SDA_HIGH();
SDA_HIGH();
}
//2开始信号函数 ok
void IIC_Start(void)
{
//B组第7个引脚设定成输出模式
SDA_OUT();
//两个都是输出高电平
SDA_HIGH();
SCL_HIGH();
//延时2微秒
delay_us(I2C_DELAY);
//数据线由高电平变成低电平
//START:when CLK is high,DATA change form high to low
SDA_LOW();
//再延时2微秒
delay_us(I2C_DELAY);
//把时钟线也拉低
SCL_LOW();
}
//3产生IIC停止信号
//STOP:when CLK is high DATA change form low to high
void IIC_Stop(void)
{
//B组第7个引脚数据线设定成输出模式
SDA_OUT();
//两个都输出低电平。
SCL_LOW();
SDA_LOW();
delay_us(I2C_DELAY);
//clk时钟线先跳到高电平。
SCL_HIGH();
delay_us(I2C_DELAY);
//数据线再由低电平跳变到高电平。
SDA_HIGH();
delay_us(I2C_DELAY);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
//将PB第7个引脚设定成输入模式,等待读取数据
SDA_IN();
//数据线高电平
SDA_HIGH();
delay_us(I2C_DELAY);
//时钟线高电平
SCL_HIGH();
delay_us(I2C_DELAY);
//数据线和时钟线两个都是高电平
//等待对面的从设备把数据线拉低。
//然后就等待,while有等待的意思,读取第7个引脚的数据。
while(READ_SDA())
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 1;
}
}
//时钟输出0
SCL_LOW();
return 0;
}
//产生ACK应答
//第9个时钟周期调用这个函数
void IIC_Ack(void)
{
//低电平期间
SCL_LOW();
//数据线设定成输出模式
SDA_OUT();
//输出低电平 数据线始终为低电平
SDA_LOW();
//延时一定时间
delay_us(I2C_DELAY);
//输出高电平,并且稳定
SCL_HIGH();
delay_us(I2C_DELAY);
//时钟线又跳到低电平:后续的电平可以变化
SCL_LOW();
}
//不产生ACK应答
void IIC_NAck(void)
{
//时钟线为低电平
SCL_LOW() ;
//设定数据线为输出模式
SDA_OUT();
//输出高电平 : 数据线始终为高电平
SDA_HIGH();
delay_us(I2C_DELAY);
//时钟线跳变到高电平
SCL_HIGH();
delay_us(I2C_DELAY);
//把时钟线拉低
SCL_LOW() ;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd) //1111 1111 & 1000 0000
{
u8 t;
//设定数据线为输出模式
SDA_OUT();
//拉低时钟开始数据传输
SCL_LOW() ;
for(t=0;t<8;t++)
{
//取出数据的最高位 右移7位,然后发送出去
if(txd & 0x80)
SDA_HIGH();
else
SDA_LOW();
//一个自己的数据左移一位,取出最高位
txd<<=1;
//对TEA5767这三个延时都是必须的
delay_us(I2C_DELAY);
//高电平区间数据稳定
SCL_HIGH();
delay_us(I2C_DELAY);
//低电平期间,数据线数据可以变化
SCL_LOW() ;
delay_us(I2C_DELAY);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
//SDA设置为输入,数据线设定为输入模式
SDA_IN();
//循环读数据
for(i=0;i<8;i++ )
{
//时钟线为低电平
SCL_LOW() ;
delay_us(I2C_DELAY);
//时钟线拉高
SCL_HIGH();
delay_us(I2C_DELAY);
//时钟线为高电平的时候,读数据
receive<<=1; //receive是读到的是二进制数值
if(READ_SDA()== 1) //如果读到了数据就把receive++,
receive++; //读的是二进制数值
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
u8 READ_SDA(void)
{
u8 sda_val=0;
sda_val=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7);
return sda_val;
}
15.oled.h
#ifndef __OLED_H__
#define __OLED_H__
#include "stm32f4xx.h"
//#include "sys.h"
/*
OLED 屏 --I2C接口
slave addr: 0x3C ,低7位
*/
#define OLED_SLAVE_ADDR_WR (0x3C<<1) //从机地址 011 11000
extern uint8_t HZ1[]; //湿
extern uint8_t HZ2[]; //温
extern uint8_t HZ3[]; //度
extern uint8_t HZ4[]; // 欢
extern uint8_t HZ5[]; //迎
extern uint8_t HZ6[]; //来
extern uint8_t HZ7[]; //到
extern uint8_t HZ8[]; // 智
extern uint8_t HZ9[]; //慧
extern uint8_t HZ10[]; //农
extern uint8_t HZ11[]; //业
//打开oled函数:初始化函数
void InitOLed(void);
//填充像素函数
void OLed_Fill(uint8_t bmp_data);
//显示字母函数
void OLed_ShowASCII(uint8_t x, uint8_t y,char *str);
//显示汉字函数
void OLed_ShowChina(uint8_t x,uint8_t y,uint8_t *buf);
//测试函数
void OLed_ShowTest(uint8_t x,uint8_t y);
//关闭oled函数
void offInitOLed(void);
//显示温度湿度
void OLed_ShowTemp(void);
#endif
16.oled.c
#include "stm32f4xx.h" //系统库文件
#include "oled.h" //oled操作函数文件
#include "myiic.h" //iic接口文件;
//======================================================
// 128X64I液晶底层驱动[8X16]字体库
// 设计者: powerint
// 描 述: [8X16]西文字符的字模数据 (纵向取模,字节倒序)
// !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
//======================================================
const unsigned char F8X16[]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//!1
0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//"2
0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//#3
0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$4
0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//%5
0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//&6
0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//'7
0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//(8
0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//)9
0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//*10
0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+11
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//,12
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//-13
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//.14
0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,///15
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//016
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//117
0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//218
0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//319
0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//420
0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//521
0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//622
0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//723
0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//824
0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//925
0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//:26
0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//;27
0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//<28
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//=29
0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//>30
0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//?31
0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@32
0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A33
0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B34
0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C35
0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D36
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E37
0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F38
0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G39
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H40
0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I41
0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J42
0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K43
0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L44
0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M45
0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N46
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O47
0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P48
0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q49
0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R50
0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S51
0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T52
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U53
0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V54
0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W55
0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X56
0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y57
0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z58
0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[59
0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\60
0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//]61
0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^62
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_63
0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//`64
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a65
0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b66
0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c67
0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d68
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e69
0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f70
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g71
0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h72
0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i73
0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j74
0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k75
0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l76
0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m77
0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n78
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o79
0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p80
0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q81
0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r82
0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s83
0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t84
0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u85
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v86
0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w87
0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x88
0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y89
0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z90
0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{91
0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//|92
0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//}93
0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~94
};
//汉字字模数据 字库字符数组
//温
uint8_t HZ1[]={
0x10,0x60,0x02,0x8C,0x00,0x00,0xFE,0x92,0x92,0x92,0x92,0x92,0xFE,0x00,0x00,0x00,
0x04,0x04,0x7E,0x01,0x40,0x7E,0x42,0x42,0x7E,0x42,0x7E,0x42,0x42,0x7E,0x40,0x00,
};
//度
uint8_t HZ2[]={
0x00,0x00,0xFC,0x24,0x24,0x24,0xFC,0x25,0x26,0x24,0xFC,0x24,0x24,0x24,0x04,0x00,
0x40,0x30,0x8F,0x80,0x84,0x4C,0x55,0x25,0x25,0x25,0x55,0x4C,0x80,0x80,0x80,0x00,
};
//湿
uint8_t HZ3[]={
0x10,0x60,0x02,0x8C,0x00,0xFE,0x92,0x92,0x92,0x92,0x92,0x92,0xFE,0x00,0x00,0x00,
0x04,0x04,0x7E,0x01,0x44,0x48,0x50,0x7F,0x40,0x40,0x7F,0x50,0x48,0x44,0x40,0x00,
};
uint8_t jj[] ={
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,
};
//;"欢",
uint8_t HZ4[] = {
0X04,0X24,0X44,0X84,0X64,0X9C,0X40,0X30,0X0F,0XC8,0X08,0X08,0X28,0X18,0X00,0X00,
0X10,0X08,0X06,0X01,0X82,0X4C,0X20,0X18,0X06,0X01,0X06,0X18,0X20,0X40,0X80,0X00,
};
//;"迎",
uint8_t HZ5[] = {
0X40,0X40,0X42,0XCC,0X00,0X00,0XFC,0X04,0X02,0X00,0XFC,0X04,0X04,0XFC,0X00,0X00,
0X00,0X40,0X20,0X1F,0X20,0X40,0X4F,0X44,0X42,0X40,0X7F,0X42,0X44,0X43,0X40,0X00,
};
//;"来",
uint8_t HZ6[] = {
0X00,0X08,0X08,0X28,0XC8,0X08,0X08,0XFF,0X08,0X08,0X88,0X68,0X08,0X08,0X00,0X00,
0X21,0X21,0X11,0X11,0X09,0X05,0X03,0XFF,0X03,0X05,0X09,0X11,0X11,0X21,0X21,0X00,
};
//;"到",
uint8_t HZ7[] = {
0X42,0X62,0X52,0X4A,0XC6,0X42,0X52,0X62,0XC2,0X00,0XF8,0X00,0X00,0XFF,0X00,0X00,
0X40,0XC4,0X44,0X44,0X7F,0X24,0X24,0X24,0X20,0X00,0X0F,0X40,0X80,0X7F,0X00,0X00,
};
//;"智",
uint8_t HZ8[] = {
0X10,0X94,0X53,0X32,0X1E,0X32,0X52,0X10,0X00,0X7E,0X42,0X42,0X42,0X7E,0X00,0X00,
0X00,0X00,0X00,0XFF,0X49,0X49,0X49,0X49,0X49,0X49,0X49,0XFF,0X00,0X00,0X00,0X00,
};
//;"慧",
uint8_t HZ9[] = {
0X22,0X2A,0XAA,0XFF,0XAA,0XAA,0XA2,0X80,0XA2,0XAA,0XAA,0XFF,0XAA,0X2A,0X22,0X00,
0X80,0X60,0X08,0X0A,0X6A,0X8A,0X8A,0X9A,0XAA,0X8A,0X8A,0XCA,0X0F,0X20,0XC0,0X00,
};
//;"农",
uint8_t HZ10[] = {
0X20,0X18,0X08,0X08,0X08,0XC8,0X38,0XCF,0X08,0X08,0X08,0X08,0XA8,0X18,0X00,0X00,
0X10,0X08,0X04,0X02,0XFF,0X40,0X20,0X00,0X03,0X04,0X0A,0X11,0X20,0X40,0X40,0X00,
};
//;"业",
uint8_t HZ11[] = {
0X00,0X10,0X60,0X80,0X00,0XFF,0X00,0X00,0X00,0XFF,0X00,0X00,0XC0,0X30,0X00,0X00,
0X40,0X40,0X40,0X43,0X40,0X7F,0X40,0X40,0X40,0X7F,0X42,0X41,0X40,0X40,0X40,0X00,
};
/*
0X04,0X24,0X44,0X84,0X64,0X9C,0X40,0X30,0X0F,0XC8,0X08,0X08,0X28,0X18,0X00,0X00,0X10,0X08,0X06,0X01,0X82,0X4C,0X20,0X18,0X06,0X01,0X06,0X18,0X20,0X40,0X80,0X00;"欢",0
0X40,0X40,0X42,0XCC,0X00,0X00,0XFC,0X04,0X02,0X00,0XFC,0X04,0X04,0XFC,0X00,0X00,0X00,0X40,0X20,0X1F,0X20,0X40,0X4F,0X44,0X42,0X40,0X7F,0X42,0X44,0X43,0X40,0X00;"迎",1
0X00,0X08,0X08,0X28,0XC8,0X08,0X08,0XFF,0X08,0X08,0X88,0X68,0X08,0X08,0X00,0X00,0X21,0X21,0X11,0X11,0X09,0X05,0X03,0XFF,0X03,0X05,0X09,0X11,0X11,0X21,0X21,0X00;"来",2
0X42,0X62,0X52,0X4A,0XC6,0X42,0X52,0X62,0XC2,0X00,0XF8,0X00,0X00,0XFF,0X00,0X00,0X40,0XC4,0X44,0X44,0X7F,0X24,0X24,0X24,0X20,0X00,0X0F,0X40,0X80,0X7F,0X00,0X00;"到",3
0X10,0X94,0X53,0X32,0X1E,0X32,0X52,0X10,0X00,0X7E,0X42,0X42,0X42,0X7E,0X00,0X00,0X00,0X00,0X00,0XFF,0X49,0X49,0X49,0X49,0X49,0X49,0X49,0XFF,0X00,0X00,0X00,0X00;"智",4
0X22,0X2A,0XAA,0XFF,0XAA,0XAA,0XA2,0X80,0XA2,0XAA,0XAA,0XFF,0XAA,0X2A,0X22,0X00,0X80,0X60,0X08,0X0A,0X6A,0X8A,0X8A,0X9A,0XAA,0X8A,0X8A,0XCA,0X0F,0X20,0XC0,0X00;"慧",5
0X20,0X18,0X08,0X08,0X08,0XC8,0X38,0XCF,0X08,0X08,0X08,0X08,0XA8,0X18,0X00,0X00,0X10,0X08,0X04,0X02,0XFF,0X40,0X20,0X00,0X03,0X04,0X0A,0X11,0X20,0X40,0X40,0X00;"农",6
0X00,0X10,0X60,0X80,0X00,0XFF,0X00,0X00,0X00,0XFF,0X00,0X00,0XC0,0X30,0X00,0X00,0X40,0X40,0X40,0X43,0X40,0X7F,0X40,0X40,0X40,0X7F,0X42,0X41,0X40,0X40,0X40,0X00;"业",7
*/
//显示温度 和湿度函数
void OLed_ShowTemp(void)
{
//第1行显示温度
OLed_ShowChina(16,0,HZ1);
OLed_ShowChina(32,0,HZ2);
OLed_ShowASCII(48,0,"111"); //显示英文。
//第2行显示湿度
OLed_ShowChina(16,2,HZ3);
OLed_ShowChina(32,2,HZ2);
}
/*
写OLED命令寄存器的函数
*/
void WriteOLedCmd(uint8_t cmd)
{
uint8_t CtrWord = 0x00;
IIC_Start();
IIC_Send_Byte(OLED_SLAVE_ADDR_WR); //发送从设备地址
IIC_Wait_Ack();
IIC_Send_Byte(CtrWord); //发送命令控制字
IIC_Wait_Ack();
IIC_Send_Byte(cmd);
IIC_Wait_Ack();
IIC_Stop();
}
/*
写OLED数据的函数
*/
void WriteOLedData(uint8_t data)
{
uint8_t CtrWord = 0x00;
CtrWord |= (0x1<<6); //表示发送的是数据
IIC_Start();
IIC_Send_Byte(OLED_SLAVE_ADDR_WR); //发送从设备地址
IIC_Wait_Ack();
IIC_Send_Byte(CtrWord); //发送命令控制字
IIC_Wait_Ack();
IIC_Send_Byte(data);
IIC_Wait_Ack();
IIC_Stop();
}
/*
设置显示位置
y--> page address页地址 ,相当于 行 (0 ~ 7) 1 100
x --> 列地址 (0 ~ 127)
*/
void OLed_SetPos(unsigned char x, unsigned char y)
{
WriteOLedCmd((0xb0+y)); //设置行地址,设置页号
WriteOLedCmd(((x&0xf0)>>4)|0x10); //设置列地址高位
WriteOLedCmd((x&0x0f)|0x00); //设置列地址的低位
}
#define X_WIDTH 128
/*
填充显示数据缓冲区
*/
void OLed_Fill(unsigned char bmp_data)
{
unsigned char y,x;
for(y=0;y<8;y++)
{
//设置PAGE地址
WriteOLedCmd(0xb0+y);
//设置列地址
WriteOLedCmd(0x00);
WriteOLedCmd(0x10);
for(x=0;x<X_WIDTH;x++)
{
WriteOLedData(bmp_data);
}
}
}
//-----------------------------------------------------//
//1 打开oled函数
void InitOLed(void)
{
//给OLED发送命令 初始化OLED
WriteOLedCmd(0xAE);//--turn off oled panel
WriteOLedCmd(0x00);//---set low column address
WriteOLedCmd(0x10);//---set high column address
WriteOLedCmd(0x40);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
WriteOLedCmd(0x81);//--set contrast control register
WriteOLedCmd(0xCF); // Set SEG Output Current Brightness
WriteOLedCmd(0xA1);//--Set SEG/Column Mapping 0xa0???? 0xa1??
WriteOLedCmd(0xC8);//Set COM/Row Scan Direction 0xc0???? 0xc8??
WriteOLedCmd(0xA6);//--set normal display
WriteOLedCmd(0xA8);//--set multiplex ratio(1 to 64)
WriteOLedCmd(0x3f);//--1/64 duty
WriteOLedCmd(0xD3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
WriteOLedCmd(0x00);//-not offset
WriteOLedCmd(0xd5);//--set display clock divide ratio/oscillator frequency
WriteOLedCmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec
WriteOLedCmd(0xD9);//--set pre-charge period
WriteOLedCmd(0xF1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
WriteOLedCmd(0xDA);//--set com pins hardware configuration
WriteOLedCmd(0x12);
WriteOLedCmd(0xDB);//--set vcomh
WriteOLedCmd(0x40);//Set VCOM Deselect Level
WriteOLedCmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)
WriteOLedCmd(0x02);//
WriteOLedCmd(0x8D);//--set Charge Pump enable/disable
WriteOLedCmd(0x14);//--set(0x10) disable
WriteOLedCmd(0xA4);// Disable Entire Display On (0xa4/0xa5)
WriteOLedCmd(0xA6);// Disable Inverse Display On (0xa6/a7)
WriteOLedCmd(0xAF);//--turn on oled panel
WriteOLedCmd(0xAF); /*display ON*/
OLed_Fill(0x00);
}
//2oled关闭函数
void offInitOLed(void)
{
//给OLED发送命令 初始化OLED
WriteOLedCmd(0xAE);//--turn off oled panel
WriteOLedCmd(0x00);//---set low column address
WriteOLedCmd(0x10);//---set high column address
WriteOLedCmd(0x40);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
WriteOLedCmd(0x81);//--set contrast control register
WriteOLedCmd(0xCF); // Set SEG Output Current Brightness
WriteOLedCmd(0xA1);//--Set SEG/Column Mapping 0xa0???? 0xa1??
WriteOLedCmd(0xC8);//Set COM/Row Scan Direction 0xc0???? 0xc8??
WriteOLedCmd(0xA6);//--set normal display
WriteOLedCmd(0xA8);//--set multiplex ratio(1 to 64)
WriteOLedCmd(0x3f);//--1/64 duty
WriteOLedCmd(0xD3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
WriteOLedCmd(0x00);//-not offset
WriteOLedCmd(0xd5);//--set display clock divide ratio/oscillator frequency
WriteOLedCmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec
WriteOLedCmd(0xD9);//--set pre-charge period
WriteOLedCmd(0xF1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
WriteOLedCmd(0xDA);//--set com pins hardware configuration
WriteOLedCmd(0x12);
WriteOLedCmd(0xDB);//--set vcomh
WriteOLedCmd(0x40);//Set VCOM Deselect Level
WriteOLedCmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)
WriteOLedCmd(0x02);//
WriteOLedCmd(0x8D);//--set Charge Pump enable/disable
WriteOLedCmd(0x14);//--set(0x10) disable
WriteOLedCmd(0xA4);// Disable Entire Display On (0xa4/0xa5)
WriteOLedCmd(0xA6);// Disable Inverse Display On (0xa6/a7)
WriteOLedCmd(0xAF);//--turn on oled panel
}
/***********************************显示3个函数*************************************************/
uint8_t fbuf1[]={0x00,0x00,0xF0,0x10,0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x10,0xF0,0x00,0x00,0x00};
uint8_t fbuf2[]={0x00,0x00,0x0F,0x04,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x04,0x0F,0x00,0x00,0x00};/*中*/
uint8_t fbuf3[]={0x00,0xFE,0x02,0x12,0x92,0x92,0x92,0xF2,0x92,0x92,0x92,0x12,0x02,0xFE,0x00,0x00};
uint8_t fbuf4[]={0x00,0xFF,0x40,0x48,0x48,0x48,0x48,0x4F,0x48,0x4A,0x4C,0x48,0x40,0xFF,0x00,0x00};/*国*/
/*
功能:在指定位置显示指定ASCII码对应字符串
@x: 显示的行号(页号0~7)
@y:显示的列号(列号0~127)
@str: 要显示的ascii的字符串
*/
//3.显示字母函数
void OLed_ShowASCII(uint8_t x, uint8_t y,char *str)
{
uint8_t i = 0;
char *pstr = str;
while(*pstr)
{
OLed_SetPos(x,y);
for(i=0;i<8;i++)
{
WriteOLedData(F8X16[((*pstr)-32)*16+i]);
}
OLed_SetPos(x,y+1);
for(i=0;i<8;i++)
{
WriteOLedData(F8X16[((*pstr)-32)*16+8+i]);
}
pstr++;
x +=8;
}
}
/*
功能: 在指定位置显示一个汉字, 显示下一个汉字时,X每次递增16
Y递增 2 字模数据 buf
*/
//4.显示汉字函数
void OLed_ShowChina(uint8_t x,uint8_t y,uint8_t *buf)
{
uint8_t i = 0;
OLed_SetPos(x,y);
for(i=0;i<16;i++)
{
WriteOLedData(buf[i]);
}
OLed_SetPos(x,(y+1));
for(i=0;i<16;i++)
{
WriteOLedData(buf[i+16]);
}
}
/*
在 x,y 位置显示
*/
void OLed_ShowTest(unsigned char x,unsigned char y)
{
uint8_t i = 0;
OLed_SetPos(x,y);
for(i=0;i<16;i++)
{
WriteOLedData(fbuf1[i]);
}
OLed_SetPos(x,(y+1));
for(i=0;i<16;i++)
{
WriteOLedData(fbuf2[i]);
}
OLed_SetPos((x+16),y);
for(i=0;i<16;i++)
{
WriteOLedData(fbuf3[i]);
}
OLed_SetPos((x+16),(y+1));
for(i=0;i<16;i++)
{
WriteOLedData(fbuf4[i]);
}
}
17.myusart.h
#ifndef __MY_USART_H__
#define __MY_USART_H__
#include "stm32f4xx_rcc.h"
#define USART_REC_LEN 50
extern u8 USART_RX_BUF[USART_REC_LEN];//数据接收的数组
extern u16 USART_RX_STA; //接受完成的标志 ,如果最高位是1 则接受完成
void myusart_init(int usart_btl);//初始化
void printt(char str[],unsigned char num);//输出函数 串口传输函数
#endif
18.myusart.c
#include "myusart.h"
#include "stm32f4xx_usart.h"
#include "stm32f4xx_gpio.h"
#include "stdio.h"
#include "string.h"
#include "delay.h"
u8 USART_RX_BUF[USART_REC_LEN];
u16 USART_RX_STA = 0; //接受完成的标志
char wendu[30] = "";
char str[128] = "\0";
char i = 0 ;
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
x=x;
}
int fputc(int ch,FILE *f)
{
#if 0
while( (USART1->SR&(1<<6))==0 ); //发送未完成等待
USART1->DR = (unsigned char)ch; //发送完成,那么可以向DR写入下一个待发送的数据
return ch;
#else
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
USART_SendData(USART1,(unsigned char)ch);
return ch;
#endif
}
int fgetc(FILE *f)
{
#if 0
while((USART1->SR&(1<<5)) == 0); //数据寄存器非空(即:接收到数据),那么跳出循环,否则一直等待
return((int)(USART1->DR&0xff)); //接收完成,读取数据。
#else
while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);
return((int)(USART_ReceiveData(USART1)));
#endif
}
void myusart_init(int usart_btl)
{
//第一步:准备三个结构体
USART_InitTypeDef USART_InitStruct; // 串口通信
NVIC_InitTypeDef NVIC_InitStruct ; // 中断寄存器NVIC
GPIO_InitTypeDef GPIO_InitStruct; //GPIO设置结构体
//第二步: 时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //串口时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //GPIO口时钟使能
//第三步: 设置端口复用
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9,GPIO_AF_USART1);
//把A组中的10引脚设置成串口1模式(复用)
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10,GPIO_AF_USART1);
//
//第四步: 设置GPIO口的模式 (PA9 --TXD PA10 ---RXD)
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF ; //复用功能
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOA ,&GPIO_InitStruct);
GPIO_SetBits(GPIOA,GPIO_Pin_9);
/*GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init( GPIOA ,&GPIO_InitStruct);*/
// 第五步: 设置usart寄存器
USART_InitStruct.USART_BaudRate = usart_btl; // 波特率
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 硬件流
USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; //允许接受和发送
USART_InitStruct.USART_Parity = USART_Parity_No; // 奇偶校验位(无)
USART_InitStruct.USART_StopBits = USART_StopBits_1; //停止位 (1位)
USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 字长 (8位)
USART_Init(USART1,&USART_InitStruct);
//第六步: 设置中断寄存器
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; // 中断号
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //终端号使能
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; // 响应优先级
NVIC_Init(&NVIC_InitStruct);
//第七步: 设置接收中断使能 设置串口使能
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //接收数据中断
USART_Cmd(USART1,ENABLE);
}
//发送数据 aabcdef\r\n
//串口1中断服务程序
u8 count = 0;
void USART1_IRQHandler(void)
{
u8 Res;
//接收中断(接收到的数据必须是0x0d 0x0a结尾)
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
//printf("111");
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d 0100 0000 0000 0000
{
if(Res!='\n')USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到‘\r’
{
if(Res=='\r')USART_RX_STA|=0x4000; //USART_RX_STA = 1100 0000 0000 0000
else //USART_RX_BUF[0] = 'd'; USART_RX_BUF[1] = 'a';.. USART_RX_BUF[4] = 'y'
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; // danny\r\n
USART_RX_STA++;
//接收数据错误,重新开始接收
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
}
}
}
}
}
void printt(char str[],unsigned char num)
{
unsigned char i = 0 ;
for(i = 0 ; i < strlen(str);i++)
{
USART_SendData(USART1,str[i]);
delay_ms(5);
}
//格式化函数,把十六进制转换成字符串
sprintf(wendu,"%d",num);
//添加一个换行符
strcat(wendu,"\r\n");
//串口打印函数
for(i = 0 ; i < strlen(wendu);i++)
{
USART_SendData(USART1,wendu[i]);
delay_ms(5);
}
}
//进行串口通信,当用户发送01+02 串口接受到后 发送03 给到pc
/*
SysTick_init(168);
//中断分组
u16 len = 0;
int i = 0;
SysTick_init(168);//初始化延时函数
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
myusart_init(115200);
while(1)
{
//数据接收完成
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
for(i=0;i<len;i++)
{
USART_SendData(USART1, USART_RX_BUF[i]);
//等待发送结束
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
}
if(len == 5)
{
if(USART_RX_BUF[2]==43)
{
int a1=((int)(USART_RX_BUF[0] -48)*10 )+ (int)(USART_RX_BUF[1] -48);
int a2=((int)(USART_RX_BUF[3] -48)*10 )+ (int)(USART_RX_BUF[4] -48);
int a3= a1+a2;
if(a3<10)
{
printf("= 0%d \r\n",a3);
}
else
{
printf("= %d \r\n",a3);
}
}
else if(USART_RX_BUF[2]==45)
{
int a1=((int)(USART_RX_BUF[0] -48)*10 )+ (int)(USART_RX_BUF[1] -48);
int a2=((int)(USART_RX_BUF[3] -48)*10 )+ (int)(USART_RX_BUF[4] -48);
int a3= a1-a2;
if(a3<10)
{
printf("= %d \r\n",a3);
}
else
{
printf("= %d \r\n",a3);
}
}
}
USART_RX_STA=0;
}
}
*/
19. PWM.h
#include "myusart.h"
#include "stm32f4xx_usart.h"
#include "stm32f4xx_gpio.h"
#include "stdio.h"
#include "string.h"
#include "delay.h"
u8 USART_RX_BUF[USART_REC_LEN];
u16 USART_RX_STA = 0; //接受完成的标志
char wendu[30] = "";
char str[128] = "\0";
char i = 0 ;
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
x=x;
}
int fputc(int ch,FILE *f)
{
#if 0
while( (USART1->SR&(1<<6))==0 ); //发送未完成等待
USART1->DR = (unsigned char)ch; //发送完成,那么可以向DR写入下一个待发送的数据
return ch;
#else
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
USART_SendData(USART1,(unsigned char)ch);
return ch;
#endif
}
int fgetc(FILE *f)
{
#if 0
while((USART1->SR&(1<<5)) == 0); //数据寄存器非空(即:接收到数据),那么跳出循环,否则一直等待
return((int)(USART1->DR&0xff)); //接收完成,读取数据。
#else
while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);
return((int)(USART_ReceiveData(USART1)));
#endif
}
void myusart_init(int usart_btl)
{
//第一步:准备三个结构体
USART_InitTypeDef USART_InitStruct; // 串口通信
NVIC_InitTypeDef NVIC_InitStruct ; // 中断寄存器NVIC
GPIO_InitTypeDef GPIO_InitStruct; //GPIO设置结构体
//第二步: 时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //串口时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //GPIO口时钟使能
//第三步: 设置端口复用
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9,GPIO_AF_USART1);
//把A组中的10引脚设置成串口1模式(复用)
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10,GPIO_AF_USART1);
//
//第四步: 设置GPIO口的模式 (PA9 --TXD PA10 ---RXD)
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF ; //复用功能
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOA ,&GPIO_InitStruct);
GPIO_SetBits(GPIOA,GPIO_Pin_9);
/*GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init( GPIOA ,&GPIO_InitStruct);*/
// 第五步: 设置usart寄存器
USART_InitStruct.USART_BaudRate = usart_btl; // 波特率
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 硬件流
USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; //允许接受和发送
USART_InitStruct.USART_Parity = USART_Parity_No; // 奇偶校验位(无)
USART_InitStruct.USART_StopBits = USART_StopBits_1; //停止位 (1位)
USART_InitStruct.USART_WordLength = USART_WordLength_8b; // 字长 (8位)
USART_Init(USART1,&USART_InitStruct);
//第六步: 设置中断寄存器
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn; // 中断号
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //终端号使能
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; // 响应优先级
NVIC_Init(&NVIC_InitStruct);
//第七步: 设置接收中断使能 设置串口使能
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //接收数据中断
USART_Cmd(USART1,ENABLE);
}
//发送数据 aabcdef\r\n
//串口1中断服务程序
u8 count = 0;
void USART1_IRQHandler(void)
{
u8 Res;
//接收中断(接收到的数据必须是0x0d 0x0a结尾)
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
//printf("111");
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d 0100 0000 0000 0000
{
if(Res!='\n')USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到‘\r’
{
if(Res=='\r')USART_RX_STA|=0x4000; //USART_RX_STA = 1100 0000 0000 0000
else //USART_RX_BUF[0] = 'd'; USART_RX_BUF[1] = 'a';.. USART_RX_BUF[4] = 'y'
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; // danny\r\n
USART_RX_STA++;
//接收数据错误,重新开始接收
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;
}
}
}
}
}
void printt(char str[],unsigned char num)
{
unsigned char i = 0 ;
for(i = 0 ; i < strlen(str);i++)
{
USART_SendData(USART1,str[i]);
delay_ms(5);
}
//格式化函数,把十六进制转换成字符串
sprintf(wendu,"%d",num);
//添加一个换行符
strcat(wendu,"\r\n");
//串口打印函数
for(i = 0 ; i < strlen(wendu);i++)
{
USART_SendData(USART1,wendu[i]);
delay_ms(5);
}
}
//进行串口通信,当用户发送01+02 串口接受到后 发送03 给到pc
/*
SysTick_init(168);
//中断分组
u16 len = 0;
int i = 0;
SysTick_init(168);//初始化延时函数
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
myusart_init(115200);
while(1)
{
//数据接收完成
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
for(i=0;i<len;i++)
{
USART_SendData(USART1, USART_RX_BUF[i]);
//等待发送结束
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
}
if(len == 5)
{
if(USART_RX_BUF[2]==43)
{
int a1=((int)(USART_RX_BUF[0] -48)*10 )+ (int)(USART_RX_BUF[1] -48);
int a2=((int)(USART_RX_BUF[3] -48)*10 )+ (int)(USART_RX_BUF[4] -48);
int a3= a1+a2;
if(a3<10)
{
printf("= 0%d \r\n",a3);
}
else
{
printf("= %d \r\n",a3);
}
}
else if(USART_RX_BUF[2]==45)
{
int a1=((int)(USART_RX_BUF[0] -48)*10 )+ (int)(USART_RX_BUF[1] -48);
int a2=((int)(USART_RX_BUF[3] -48)*10 )+ (int)(USART_RX_BUF[4] -48);
int a3= a1-a2;
if(a3<10)
{
printf("= %d \r\n",a3);
}
else
{
printf("= %d \r\n",a3);
}
}
}
USART_RX_STA=0;
}
}
*/
20. PWM.c
#include "pwm.h"
#include "stm32f4xx.h"
#include "delay.h"
//TIM14 PWM部分初始化
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM14_PWM_Init(void)
{
//此部分需手动修改IO口设置
GPIO_InitTypeDef GPIO_InitStructure;
//定时器结构体初始化。
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
//1TIM14时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
2使能PORTF时钟
TIM_DeInit(TIM1);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
//3GPIOF9复用为定时器14 // Device header
GPIO_PinAFConfig(GPIOE,GPIO_PinSource8,GPIO_AF_TIM1);
//GPIOF9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
//复用功能
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
//速度100MHz
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
//推挽复用输出
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
//上拉
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
//4初始化PF9
GPIO_Init(GPIOE,&GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Prescaler=400; //定时器分频
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseStructure.TIM_Period=100; //自动重装载值
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
// TIM_TimeBaseStructure.TIM_RepetitionCounter = 1;
//5初始化定时器14
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);
//初始化TIM14 Channel1 PWM模式
//选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
//6根据T指定的参数初始化外设TIM1 4OC1
// TIM_OCInitStructure.TIM_Pulse = 100;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
//7使能TIM14在CCR1上的预装载寄存器
// TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
// //8ARPE使能
// TIM_ARRPreloadConfig(TIM1,ENABLE);
//9使能TIM14
TIM_Cmd(TIM1, ENABLE);
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
void ppp(int a)// 呼吸灯
{
static u16 led0pwmval=0;
if(a<0)
{
led0pwmval=0;
}
else if(a>=100)
{
led0pwmval=100;
}
else
{
led0pwmval =a;
}
//修改比较值,修改占空比
TIM_SetCompare1(TIM1,led0pwmval);
}
21.wwdg.h
#ifndef __WWDG_H__
#define __WWDG_H__
void wwdginit(void);//窗口看门狗初始化
#endif
22.wwdg.c
#include "stm32f4xx.h"
#include "wwdg.h"
#include "delay.h"
#include "misc.h"
//当前值寄存器从自定义 0x7f 递减
//0x5f:自定的窗口上限值
//0x3f:固定的串口下限值
//只有窗口期才可以喂狗,如果喂狗,系统就不会重启,否则,如果没有配置中断功能,程序就会重启。
//如果窗口期没有喂狗,自动进入到中断函数中。可以在中断函数中进行喂狗。
//窗口看门狗可以配置中断。
void wwdginit()
{
//1.配置时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);
//2设置分频值:WWDG_Prescaler_8
WWDG_SetPrescaler(WWDG_Prescaler_8);
//3设置窗口值 : 窗口上限值。只要比 0x3f大就行。
WWDG_SetWindowValue(0x6F);
//4.开启看门狗
WWDG_Enable(0x7F);
//5.配置窗口看门狗中断类型
NVIC_InitTypeDef wwdgstruct;
wwdgstruct.NVIC_IRQChannel= WWDG_IRQn;
//抢占优先级为2
wwdgstruct.NVIC_IRQChannelPreemptionPriority=0x00;
wwdgstruct.NVIC_IRQChannelSubPriority=0x00;
//子优先级为3
wwdgstruct.NVIC_IRQChannelCmd=ENABLE;
//使能窗口看门狗中断
NVIC_Init(&wwdgstruct);
//6清除提前唤醒中断标志位:防止提前进入中断函数中。
WWDG_ClearFlag();
//7开启中断函数使能.让窗口看门狗可以使用中断功能
WWDG_EnableIT();
}
//窗口看门狗中断函数一定是这个。
//1.有没有进入中断函数中 ok
//2.为什么一直重启? 时间问题。
void WWDG_IRQHandler(void)
{
//重设窗口看门狗值 喂狗 防止重启
WWDG_SetCounter(0x5f); //0x7f - 0x3f : 0x5f - 0x3f ;
//清除提前唤醒中断标志位
WWDG_ClearFlag();
//喂狗的数值一定要在窗口期内:一定要在5f - 3f之间
}
上位机的系统文件
23. delay.h
#ifndef __DELAY_H
#define __DELAY_H
#include <sys.h>
//
void delay_init(u8 SYSCLK);
void delay_ms(u16 nms);
void delay_us(u32 nus);
#endif
24.delay.c
#include "delay.h"
#include "sys.h"
#include "misc.h"
//
//如果使用OS,则包括下面的头文件(以ucos为例)即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h" //支持OS时,使用
#endif
//
//********************************************************************************
//
static u8 fac_us=0; //us延时倍乘数
static u16 fac_ms=0; //ms延时倍乘数,在os下,代表每个节拍的ms数
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS定义了,说明要支持OS了(不限于UCOS).
//当delay_us/delay_ms需要支持OS的时候需要三个与OS相关的宏定义和函数来支持
//首先是3个宏定义:
// delay_osrunning:用于表示OS当前是否正在运行,以决定是否可以使用相关函数
//delay_ostickspersec:用于表示OS设定的时钟节拍,delay_init将根据这个参数来初始哈systick
// delay_osintnesting:用于表示OS中断嵌套级别,因为中断里面不可以调度,delay_ms使用该参数来决定如何运行
//然后是3个函数:
// delay_osschedlock:用于锁定OS任务调度,禁止调度
//delay_osschedunlock:用于解锁OS任务调度,重新开启调度
// delay_ostimedly:用于OS延时,可以引起任务调度.
//本例程仅作UCOSII和UCOSIII的支持,其他OS,请自行参考着移植
//支持UCOSII
#ifdef OS_CRITICAL_METHOD //OS_CRITICAL_METHOD定义了,说明要支持UCOSII
#define delay_osrunning OSRunning //OS是否运行标记,0,不运行;1,在运行
#define delay_ostickspersec OS_TICKS_PER_SEC //OS时钟节拍,即每秒调度次数
#define delay_osintnesting OSIntNesting //中断嵌套级别,即中断嵌套次数
#endif
//支持UCOSIII
#ifdef CPU_CFG_CRITICAL_METHOD //CPU_CFG_CRITICAL_METHOD定义了,说明要支持UCOSIII
#define delay_osrunning OSRunning //OS是否运行标记,0,不运行;1,在运行
#define delay_ostickspersec OSCfg_TickRate_Hz //OS时钟节拍,即每秒调度次数
#define delay_osintnesting OSIntNestingCtr //中断嵌套级别,即中断嵌套次数
#endif
//us级延时时,关闭任务调度(防止打断us级延迟)
void delay_osschedlock(void)
{
#ifdef CPU_CFG_CRITICAL_METHOD //使用UCOSIII
OS_ERR err;
OSSchedLock(&err); //UCOSIII的方式,禁止调度,防止打断us延时
#else //否则UCOSII
OSSchedLock(); //UCOSII的方式,禁止调度,防止打断us延时
#endif
}
//us级延时时,恢复任务调度
void delay_osschedunlock(void)
{
#ifdef CPU_CFG_CRITICAL_METHOD //使用UCOSIII
OS_ERR err;
OSSchedUnlock(&err); //UCOSIII的方式,恢复调度
#else //否则UCOSII
OSSchedUnlock(); //UCOSII的方式,恢复调度
#endif
}
//调用OS自带的延时函数延时
//ticks:延时的节拍数
void delay_ostimedly(u32 ticks)
{
#ifdef CPU_CFG_CRITICAL_METHOD
OS_ERR err;
OSTimeDly(ticks,OS_OPT_TIME_PERIODIC,&err);//UCOSIII延时采用周期模式
#else
OSTimeDly(ticks); //UCOSII延时
#endif
}
//systick中断服务函数,使用OS时用到
void SysTick_Handler(void)
{
if(delay_osrunning==1) //OS开始跑了,才执行正常的调度处理
{
OSIntEnter(); //进入中断
OSTimeTick(); //调用ucos的时钟服务程序
OSIntExit(); //触发任务切换软中断
}
}
#endif
//初始化延迟函数
//当使用OS的时候,此函数会初始化OS的时钟节拍
//SYSTICK的时钟固定为AHB时钟的1/8
//SYSCLK:系统时钟频率
void delay_init(u8 SYSCLK)
{
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
u32 reload;
#endif
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
fac_us=SYSCLK/8; //不论是否使用OS,fac_us都需要使用
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
reload=SYSCLK/8; //每秒钟的计数次数 单位为M
reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec设定溢出时间
//reload为24位寄存器,最大值:16777216,在168M下,约合0.7989s左右
fac_ms=1000/delay_ostickspersec; //代表OS可以延时的最少单位
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断
SysTick->LOAD=reload; //每1/delay_ostickspersec秒中断一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
#else
fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数
#endif
}
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
//延时nus
//nus:要延时的us数.
//nus:0~204522252(最大值即2^32/fac_us@fac_us=21)
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //LOAD的值
ticks=nus*fac_us; //需要的节拍数
delay_osschedlock(); //阻止OS调度,防止打断us延时
told=SysTick->VAL; //刚进入时的计数器值
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow<told)tcnt+=told-tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了.
else tcnt+=reload-tnow+told;
told=tnow;
if(tcnt>=ticks)break; //时间超过/等于要延迟的时间,则退出.
}
};
delay_osschedunlock(); //恢复OS调度
}
//延时nms
//nms:要延时的ms数
//nms:0~65535
void delay_ms(u16 nms)
{
if(delay_osrunning&&delay_osintnesting==0)//如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度)
{
if(nms>=fac_ms) //延时的时间大于OS的最少时间周期
{
delay_ostimedly(nms/fac_ms); //OS延时
}
nms%=fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时
}
delay_us((u32)(nms*1000)); //普通方式延时
}
#else //不用ucos时
//延时nus
//nus为要延时的us数.
//注意:nus的值,不要大于798915us(最大值即2^24/fac_us@fac_us=21)
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD=nus*fac_us; //时间加载
SysTick->VAL=0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
//延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对168M条件下,nms<=798ms
void delay_xms(u16 nms)
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)
SysTick->VAL =0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
//延时nms
//nms:0~65535
void delay_ms(u16 nms)
{
u8 repeat=nms/540; //这里用540,是考虑到某些客户可能超频使用,
//比如超频到248M的时候,delay_xms最大只能延时541ms左右了
u16 remain=nms%540;
while(repeat)
{
delay_xms(540);
repeat--;
}
if(remain)delay_xms(remain);
}
#endif
25. sys.h
#ifndef __SYS_H
#define __SYS_H
#include "stm32f4xx.h"
//
//
//0,不支持ucos
//1,支持ucos
#define SYSTEM_SUPPORT_OS 0 //定义系统文件夹是否支持UCOS
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).M4同M3类似,只是寄存器地址变了.
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr (GPIOB_BASE+20) //0x40020414
#define GPIOC_ODR_Addr (GPIOC_BASE+20) //0x40020814
#define GPIOD_ODR_Addr (GPIOD_BASE+20) //0x40020C14
#define GPIOE_ODR_Addr (GPIOE_BASE+20) //0x40021014
#define GPIOF_ODR_Addr (GPIOF_BASE+20) //0x40021414
#define GPIOG_ODR_Addr (GPIOG_BASE+20) //0x40021814
#define GPIOH_ODR_Addr (GPIOH_BASE+20) //0x40021C14
#define GPIOI_ODR_Addr (GPIOI_BASE+20) //0x40022014
#define GPIOA_IDR_Addr (GPIOA_BASE+16) //0x40020010
#define GPIOB_IDR_Addr (GPIOB_BASE+16) //0x40020410
#define GPIOC_IDR_Addr (GPIOC_BASE+16) //0x40020810
#define GPIOD_IDR_Addr (GPIOD_BASE+16) //0x40020C10
#define GPIOE_IDR_Addr (GPIOE_BASE+16) //0x40021010
#define GPIOF_IDR_Addr (GPIOF_BASE+16) //0x40021410
#define GPIOG_IDR_Addr (GPIOG_BASE+16) //0x40021810
#define GPIOH_IDR_Addr (GPIOH_BASE+16) //0x40021C10
#define GPIOI_IDR_Addr (GPIOI_BASE+16) //0x40022010
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入
#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入
#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入
#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入
#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入
#define PHout(n) BIT_ADDR(GPIOH_ODR_Addr,n) //输出
#define PHin(n) BIT_ADDR(GPIOH_IDR_Addr,n) //输入
#define PIout(n) BIT_ADDR(GPIOI_ODR_Addr,n) //输出
#define PIin(n) BIT_ADDR(GPIOI_IDR_Addr,n) //输入
//以下为汇编函数
void WFI_SET(void); //执行WFI指令
void INTX_DISABLE(void);//关闭所有中断
void INTX_ENABLE(void); //开启所有中断
void MSR_MSP(u32 addr); //设置堆栈地址
#endif
26.sys.c
#include "sys.h"
//
//
//THUMB指令不支持汇编内联
//采用如下方法实现执行汇编指令WFI
__asm void WFI_SET(void)
{
WFI;
}
//关闭所有中断(但是不包括fault和NMI中断)
__asm void INTX_DISABLE(void)
{
CPSID I
BX LR
}
//开启所有中断
__asm void INTX_ENABLE(void)
{
CPSIE I
BX LR
}
//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(u32 addr)
{
MSR MSP, r0 //set Main Stack value
BX r14
}
下位机程序
27. ui 界面代码:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1079</width>
<height>499</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QSplitter" name="splitter">
<property name="geometry">
<rect>
<x>11</x>
<y>11</y>
<width>469</width>
<height>374</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>串口控制</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>串口号</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_portName"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>波特率</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_BaudRate">
<item>
<property name="text">
<string>9600</string>
</property>
</item>
<item>
<property name="text">
<string>115200</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>数据位</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_DataBits">
<item>
<property name="text">
<string>8</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>校验位</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_Parity">
<item>
<property name="text">
<string>无校验</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>停止位</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_StopBits">
<item>
<property name="text">
<string>1</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="pushButton_open">
<property name="text">
<string>打开串口</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_led">
<property name="text">
<string>打开小灯</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_beep">
<property name="text">
<string>打开蜂鸣器</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>获取温湿度数据</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="groupBox_data">
<property name="enabled">
<bool>false</bool>
</property>
<property name="title">
<string>串口数据</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>接收数据</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTextBrowser" name="textBrowser_read"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>发送数据</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>内容:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_send">
<property name="text">
<string>发送</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLineEdit" name="lineEdit_send"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QListWidget" name="listWidget">
<property name="geometry">
<rect>
<x>490</x>
<y>0</y>
<width>251</width>
<height>381</height>
</rect>
</property>
</widget>
<widget class="QDial" name="dial">
<property name="geometry">
<rect>
<x>850</x>
<y>120</y>
<width>171</width>
<height>201</height>
</rect>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1079</width>
<height>26</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
28. mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
/***** 串口模块 ******/
#include <QSerialPort> //串口类
#include <QSerialPortInfo> //串口属性类 { 获取系统可用的串口 }
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public:
void GetSystenSerilPort(); /*** 获取系统可用串口列表,并打印到UI界面 ***/
private:
Ui::MainWindow *ui;
QSerialPort *SerialPort; /** 串口类 **/
QString data11;
public slots:
void slot_pushButton_open();
void slot_pushButton_send();
void slot_SerialPort_readyRead();
private slots:
void on_pushButton_led_clicked();
void on_pushButton_beep_clicked();
void on_pushButton_clicked();
void on_dial_valueChanged(int value);
};
#endif // MAINWINDOW_H
29. mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*** 申请串口类对象空间 ****/
SerialPort = new QSerialPort(this);
/*** 类构造时就获取系统可用串口列表 ***/
GetSystenSerilPort();
/*** 连接槽函数 ****/
connect(ui->pushButton_open,SIGNAL(clicked(bool)),this,SLOT(slot_pushButton_open()));
connect(SerialPort,SIGNAL(readyRead()),this,SLOT(slot_SerialPort_readyRead()));
connect(ui->pushButton_send,SIGNAL(clicked(bool)),this,SLOT(slot_pushButton_send()));
}
void MainWindow::slot_pushButton_send()
{
QString text = ui->lineEdit_send->text();
SerialPort->write(text.toUtf8());
}
void MainWindow::slot_SerialPort_readyRead()
{
QByteArray data = SerialPort->readAll();
ui->textBrowser_read->append(data);
QString a= QString(data);
if(a=="\r" || a=="\n")
{
data11.clear();
return;
}
data11+=a;
if(data11.size()>=7)
{
ui->listWidget->clear();
ui->listWidget->addItem(data11);
data11=data11.right(2);
QString kk=QString("温度: ")+data11;
ui->listWidget->addItem(kk);
data11.clear();
}
}
#include <QMessageBox> /*** 标准对话框 ****/
void MainWindow::slot_pushButton_open()
{
/******* 设置串口属性 ******/
SerialPort->setPortName(ui->comboBox_portName->currentText()); //设置串口号
SerialPort->setBaudRate(ui->comboBox_BaudRate->currentText().toInt()); //设置波特率
if(ui->comboBox_DataBits->currentText() == "8"){
SerialPort->setDataBits(QSerialPort::Data8); //设置数据位为8位
}
if(ui->comboBox_Parity->currentText() == "无校验"){
SerialPort->setParity(QSerialPort::NoParity); //设置校验位为无校验
}
if(ui->comboBox_StopBits->currentText() == "1"){
SerialPort->setStopBits(QSerialPort::OneStop); //设置停止位为1位
}
/***** 打开串口 ****/
bool ok = false;
if(ui->pushButton_open->text() == "打开串口")
{
ok = SerialPort->open(QIODevice::ReadWrite);
if(ok == true) //串口打开成功
{
ui->groupBox_data->setEnabled(true);
ui->pushButton_open->setText("关闭串口");
}
else
{
QMessageBox::warning(this,"警告","串口打开失败,请检查串口参数或串口已被占用");
return ;
}
}else
{
SerialPort->close(); //关闭串口
ui->pushButton_open->setText("打开串口");
ui->groupBox_data->setEnabled(false);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::GetSystenSerilPort()
{
QList<QSerialPortInfo> list_SerialPortInfo = QSerialPortInfo::availablePorts(); /*** 获取系统可用串口列表 ***/
ui->comboBox_portName->clear(); /** 清空 串口号的下拉选项框 ***/
for(QSerialPortInfo value : list_SerialPortInfo)
{
ui->comboBox_portName->addItem(value.portName()); /*** 将串口名称添加到 UI 的串口号下拉选项框中 ***/
}
}
void MainWindow::on_pushButton_led_clicked()//打开小灯
{
if(ui->pushButton_led->text() == "打开小灯")
{
qDebug()<<"打开小灯发送成功";
ui->pushButton_led->setText("关闭小灯");
QString text=QString("1\r\n");
SerialPort->write(text.toLocal8Bit());
}
else
{
qDebug()<<"关闭小灯发送成功";
ui->pushButton_led->setText("打开小灯");
QString text=QString("2\r\n");
SerialPort->write(text.toLocal8Bit());
}
}
void MainWindow::on_pushButton_beep_clicked()//打开蜂鸣器
{
if(ui->pushButton_beep->text() == "打开蜂鸣器")
{
qDebug()<<"打开蜂鸣器发送成功";
ui->pushButton_beep->setText("关闭蜂鸣器");
QString text=QString("3\r\n");
SerialPort->write(text.toLocal8Bit());
}
else
{
qDebug()<<"关闭蜂鸣器发送成功";
QString text=QString("4\r\n");
SerialPort->write(text.toLocal8Bit());
ui->pushButton_beep->setText("打开蜂鸣器");
}
}
void MainWindow::on_pushButton_clicked()//获取温湿度
{
qDebug()<<"获取温湿度发送成功";
QString text=QString("5\r\n");
SerialPort->write(text.toLocal8Bit());
}
void MainWindow::on_dial_valueChanged(int value)
{
qDebug()<<"旋钮转动";
QString text=QString("0") + QString::number(value) + QString("\r\n");
SerialPort->write(text.toLocal8Bit());
}
mian.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}