系统功能
该方案基于STM32芯片作为主控单元,实现了对温湿度、土壤PH值和湿度等数据的实时监测。通过触摸屏界面,用户可以方便地控制灯、水泵、电机等设备的开启或关闭。此外,该系统还支持连接ESP32网络模块,实现了通过APP实时查看植物生长情况的功能。
系统的关键模块包括温湿度传感器模块、PH传感器模块、土壤湿度传感器模块、串口屏幕模块、ADC模块、继电器模块和电机驱动模块。温湿度传感器模块采用DHT11传感器获取环境温湿度数据。PH传感器模块用于获取土壤的PH值。土壤湿度传感器模块实时监测土壤湿度情况。串口屏幕模块通过串口屏幕显示各种数据和交互界面。ADC模块实现模拟信号的采集和处理。继电器模块控制灯、水泵等设备的开关。电机驱动模块用于驱动各种电机执行器的工作。
系统框架图
各模块的作用
1.温湿度传感器——DHT11
其精度湿度±5%RH, 温度±2℃,
量程湿度20-90%RH, 温度0~50℃
接线图
2.PH传感器
模块使用5V电源供电,3个104规格的电容滤波,并通过LED2指示模块的工作状态。J3选用BNC(Q9)接口作值为PH电极信号的输入,输出则分为两路输出:上模拟信号输出,输出电压最大值5V;下数字信号输出。仅使用模拟信号输出部分电路。
参比电极的电压固定,为参考电压,即PH-信号电压;玻璃电极的电压随PH值的变化而变化,即PH+信号电压。TLC4502芯片是双通道运算放大器,PH+信号通过其中一路放大器2倍放大后,一路通过排针经分压电路分压后与MCU的PA1引脚相连;另一路则作为数字信号处理部分的输入,后经LM358运算放大器比较后输出高低电平, 阈值(高低电平临界值)通过调节R23电位器设置。TLC4502芯片的另外一路放大器则作为PH-信号的跟随器使用。
3.土壤湿度传感器
该传感器具有数字开关量输出(0和1)和模拟量AO电压输出两种输出形式。
接上5V电源,电源灯亮,当湿度低于设定的阈值时,DO输出为高电平,开关指示灯灭;高于设定的阈值时,DO输出为低电平,开关指示灯亮。AO模拟输出,可以连接单片机的AD口检测土壤湿度精确数值。
电位器是用于土壤湿度的阀值调节,顺时针调节,控制的湿度会越大,逆时针越小,通过电位器调节土壤湿度阈值,当土壤湿度低于设定的阈值时,模块输出高电平,高于设定的阈值时,模块输出低电平。
4.串口屏幕
水课设经常使用的模块,看起来使自己作品变的高级一点。
屏幕使用的是淘晶池的串口屏,显示内容可以通过官方上位机来编辑,屏幕学习平台:http://wiki.tjc1688.com/doku.php?id=start
通信原理:屏幕里实际也是由单片机在驱动,在屏幕上的操作,最终会变成数据通过底层单片机的串口发送到我们的单片机串口上,就能控制自己的单片机做出相应操作,同时自己的单片机也能发送屏幕能识别的特殊指令到屏幕的单片机里,实现屏幕切换页面等操作
总体流程图
1.main函数
#include "stm32f10x.h" // Device header
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include <string.h>
#include "dht11.h"
#include "GM.h"
#include "motor.h"
#include "key.h"
u8 idfind(u8 *buf,u8 *val,u8 len);
void HMISends(char *buf1);
void HMISendb(u8 buf);
void beepms(u16 va);
void pd(void);
u8 key,beep;
int sd,b=1;
extern unsigned int rec_data[4];
extern int ph,y;
void beepms(u16 va)
{
beep=1;
delay_ms(va);
beep=0;
}
void HMISendstart(void)
{
delay_ms(200);
HMISendb(0xff);
delay_ms(200);
}
int main(void)
{
delay_init(); //延时函数初始化
NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(9600); //串口初始化为9600
HMISendstart(); //为确保串口HMI正常通信
GPIO_init(); //电机GPIO初始化
RELAY_Init(); //继电器初始化
gz_Init(); //光敏电阻初始化
adc_Init(); //PH和土壤湿度的ADC初始化
PWM_Init(); //电机频率初始化
while(1)
{
DHT11_REC_Data(); //接收温度和湿度的数据
//定义一个字符串数组
char tjcstr[100];
sd=Get_ADC_Val();//土壤湿度
PH();
pd();
/*用sprintf来格式化字符串,给t0的txt属性赋值,
给控件的文本属性赋值时,内容需要用成对的 \" \" 包裹住,
当格式化的参数为字符串时,请保证字符串以\0结尾
*****************************************/
sprintf(tjcstr, "msg3.txt=\"%d.%d%\"",sd,b);
//把字符串发送出去
HMISends(tjcstr);
//发送结束符
HMISendb(0xff);
sprintf(tjcstr, "msg1.txt=\"%d.%d\"",rec_data[2],rec_data[3]);
//把字符串发送出去
HMISends(tjcstr);
//发送结束符
HMISendb(0xff);
sprintf(tjcstr, "msg2.txt=\"%d.%d\"", rec_data[0],rec_data[1]);
//把字符串发送出去
HMISends(tjcstr);
//发送结束符
HMISendb(0xff);
sprintf(tjcstr, "msg0.txt=\"%d.%d\"", ph,y);
//把字符串发送出去
HMISends(tjcstr);
//发送结束符
HMISendb(0xff);
delay_ms(100);
}
}
void pd(void)
{
if(sd<25){RELAY_1(1);delay_ms(3000);RELAY_1(0);}
if(rec_data[2]>35)MOTOR1(35);
if(ph>10){RELAY_1(1);delay_ms(3000);RELAY_1(0);}
if(L==1)RELAY_2(1);else RELAY_2(0);
}
//字符串发送函数
void HMISends(char *buf1)
{
u8 i=0;
while(1)
{
if(buf1[i] != 0)
{
USART_SendData(USART1,buf1[i]); //发送一个字节
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET){};//等待发送结束
i++;
}
else
{
return ;
}
}
}
//字节发送函数
void HMISendb(u8 k)
{
u8 i;
for(i=0; i<3; i++)
{
if(k != 0)
{
USART_SendData(USART1,k); //发送一个字节
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET){};//等待发送结束
}
else
{
return ;
}
}
}
2.ADC模块
#include "GM.h"
#include "delay.h"
#define LSENS_READ_TIMES 10 //定义光敏传感器读取次数,读10次,然后取平均值//
float PH_Value,TBD_Vol,TDS_Vol;
#define offset 25.54
void gz_Init(void)//光敏电阻
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); //APB2外设时钟使能
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_9; //选择端口号(0~15或all)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //选择IO接口工作方式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz)
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void adc_Init(void)//用的是PA0引脚,ADC1通道0
{
GPIO_InitTypeDef GM;
ADC_InitTypeDef adc1_GM;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72/6=12Mhz,不能超过14MHZ
GM.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
GM.GPIO_Pin = GPIO_Pin_1;
GM.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GM);
GM.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
GM.GPIO_Pin = GPIO_Pin_0;
GM.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GM);
adc1_GM.ADC_ContinuousConvMode = DISABLE;//单次转换
adc1_GM.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
adc1_GM.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//选软件启动
adc1_GM.ADC_Mode = ADC_Mode_Independent;//独立模式
adc1_GM.ADC_NbrOfChannel = 1;//设置转换的通道数量
adc1_GM.ADC_ScanConvMode = DISABLE;//配置为单通道模式
ADC_Init(ADC1, &adc1_GM);//初始化
ADC_Cmd(ADC1, ENABLE); //使能时钟
ADC_ResetCalibration(ADC1);//复位校准器
while ( ADC_GetResetCalibrationStatus(ADC1));//复位校准器状态
ADC_StartCalibration(ADC1);//开始校准
while(ADC_GetCalibrationStatus(ADC1));//等待校准
}
u16 get_GM_val2(void)
{
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_41Cycles5);//规则通道配置函数
ADC_SoftwareStartConvCmd(ADC1,ENABLE);//启动软件
while(!(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==SET));//等待EOC位置1
return ADC_GetConversionValue(ADC1);//返回ADC1通道采集到的数据
}
//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)
{
//设置指定ADC的规则组通道,一个序列,采样时间
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道,采样时间为239.5周期
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
}
u16 Get_Adc_Average(u8 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}
//0-14
int ph,y;
void PH(void)
{
u16 tp,TEMP;
float temp,TP,PH_Vol;
tp=Get_Adc_Average(ADC_Channel_1,10);//采样10次,取平均
temp=(float)tp*(3.3/4096);//12位ADC,参考电压3.3V被分成4096份,转换为5V参考
tp=temp;
PH_Vol=temp;
PH_Value=-5.4*PH_Vol+offset;
if(PH_Value<=0) PH_Value = 0; //PH值小于0 矫正为0
else if(PH_Value>=14) PH_Value = 14; //PH值大于14 矫正为14
ph=PH_Value-1;
/***********PH值**********/
//LCD_ShowxNum(5+18,35,PH_Value,2,12,RED,0);//整数部分
// OLED_ShowNum(3,7,PH_Value-1,2);
//小数部分
TEMP=PH_Value;
TP=PH_Value-TEMP;
TP*=100;
y=TP;
temp-=tp;
temp*=1000;
}
//范围0-100
u8 Get_ADC_Val(void)
{
u32 temp_val=0;
u8 t;
for(t=0;t<LSENS_READ_TIMES;t++) //LSENS_READ_TIMES在lsens.h文件中设好,默认10//
{
temp_val+=get_GM_val2();
delay_ms(2);
}
temp_val/=LSENS_READ_TIMES; //计算平均值//
if(temp_val>4000)temp_val=4000; //当计算后的值大于4000时,强制转换为4000/
return (u8)(100-(temp_val/40)); //将temp_val值归一化到0-100之间//
}
#ifndef __GM_H
#define __GM_H
#include "stm32f10x.h" // Device header
void gz_Init(void);
void adc_Init(void);
u16 get_GM_val2(void);
u8 Get_ADC_Val2(u8 ch);
u16 Get_Adc(u8 ch);
void PH(void);
u8 Get_ADC_Val(void);
#define L GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9)
#endif
3.DHT11-温湿度模块
#include "stm32f10x.h" // Device header
#include "dht11.h"
#include "delay.h"
//数据
unsigned int rec_data[4];
//对于stm32来说,是输出
void DH11_GPIO_Init_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//对于stm32来说,是输入
void DH11_GPIO_Init_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//主机发送开始信号
void DHT11_Start(void)
{
DH11_GPIO_Init_OUT(); //输出模式
dht11_high; //先拉高
delay_us(30);
dht11_low; //拉低电平至少18us
delay_ms(20);
dht11_high; //拉高电平20~40us
delay_us(30);
DH11_GPIO_Init_IN(); //输入模式
}
//获取一个字节
char DHT11_Rec_Byte(void)
{
unsigned char i = 0;
unsigned char data;
for(i=0;i<8;i++) //1个数据就是1个字节byte,1个字节byte有8位bit
{
while( Read_Data == 0); //从1bit开始,低电平变高电平,等待低电平结束
delay_us(30); //延迟30us是为了区别数据0和数据1,0只有26~28us
data <<= 1; //左移
if( Read_Data == 1 ) //如果过了30us还是高电平的话就是数据1
{
data |= 1; //数据+1
}
while( Read_Data == 1 ); //高电平变低电平,等待高电平结束
}
return data;
}
//获取数据
void DHT11_REC_Data(void)
{
unsigned int R_H,R_L,T_H,T_L;
unsigned char RH,RL,TH,TL,CHECK;
DHT11_Start(); //主机发送信号
dht11_high; //拉高电平
if( Read_Data == 0 ) //判断DHT11是否响应
{
while( Read_Data == 0); //低电平变高电平,等待低电平结束
while( Read_Data == 1); //高电平变低电平,等待高电平结束
R_H = DHT11_Rec_Byte();
R_L = DHT11_Rec_Byte();
T_H = DHT11_Rec_Byte();
T_L = DHT11_Rec_Byte();
CHECK = DHT11_Rec_Byte(); //接收5个数据
dht11_low; //当最后一bit数据传送完毕后,DHT11拉低总线 50us
delay_us(55); //这里延时55us
dht11_high; //随后总线由上拉电阻拉高进入空闲状态。
if(R_H + R_L + T_H + T_L == CHECK) //和检验位对比,判断校验接收到的数据是否正确
{
RH = R_H;
RL = R_L;
TH = T_H;
TL = T_L;
}
}
if(TH>80)TH=25;
rec_data[0] = RH;
rec_data[1] = RL;
rec_data[2] = TH;
rec_data[3] = TL;
delay_ms(200);
}
#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f10x.h" // Device header
#define dht11_high GPIO_SetBits(GPIOB, GPIO_Pin_5)
#define dht11_low GPIO_ResetBits(GPIOB, GPIO_Pin_5)
#define Read_Data GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_5)
void DHT11_GPIO_Init_OUT(void);
void DHT11_GPIO_Init_IN(void);
void DHT11_Start(void);
unsigned char DHT11_REC_Byte(void);
void DHT11_REC_Data(void);
#endif
4.继电器模块
#include "stm32f10x.h"
void RELAY_Init(void)
{ //继电器的接口初始化
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); //APB2外设时钟使能
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_10| GPIO_Pin_11; //选择端口号(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(GPIOB, &GPIO_InitStructure);
GPIO_ResetBits(GPIOB,GPIO_Pin_10| GPIO_Pin_11); //都为低电平(0) 初始为关继电器
}
void RELAY_1(u8 c)
{ //继电器的控制程序(c=0继电器放开,c=1继电器吸合)
GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)(c));//通过参数值写入接口
}
void RELAY_2(u8 c)
{ //继电器的控制程序(c=0继电器放开,c=1继电器吸合)
GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)(c));//通过参数值写入接口
}
#ifndef __KEY_H
#define __KEY_H
void RELAY_Init(void);
void RELAY_1(u8 c);
void RELAY_2(u8 c);
#endif
5.电机驱动
#include "motor.h"
//使用定时器2
void GPIO_init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_13|GPIO_Pin_12|GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
TIM_InternalClockConfig(TIM2);
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC3Init(TIM2, &TIM_OCInitStructure);
TIM_OC4Init(TIM2, &TIM_OCInitStructure);
TIM_Cmd(TIM2, ENABLE);
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_OC2Init(TIM3, &TIM_OCInitStructure);
TIM_Cmd(TIM3, ENABLE);
}
void MOTOR1(u8 s)
{
TIM_SetCompare3(TIM2,s);
IN1 = 1;
IN2 = 0;
}
void MOTOR2(u8 s)
{
TIM_SetCompare4(TIM2,s);
IN3 = 1;
IN4 = 0;
}
void MOTOR3(u8 s)
{
TIM_SetCompare1(TIM3,s);
IN5 = 1;
IN6 = 0;
}
void MOTOR4(u8 s)
{
TIM_SetCompare2(TIM3,s);
IN7 = 1;
IN8 = 0;
}
#ifndef __MOTOR_H
#define __MOTOR_H
#include "sys.h"
#include "stm32f10x.h" // Device header
#define IN1 PBout(12)
#define IN2 PBout(13)
#define IN3 PAout(4)
#define IN4 PAout(5)
#define IN5 PBout(14)
#define IN6 PBout(15)
#define IN7 PBout(0)
#define IN8 PBout(1)
void PWM_Init(void);
void MOTOR1(u8 s);
void MOTOR2(u8 s);
void MOTOR3(u8 s);
void MOTOR4(u8 s);
void GPIO_init(void);
#endif
6.串口屏幕通信
#include "sys.h"
#include "usart.h"
#include "key.h"
#include "motor.h"
void sjcl(void);
//
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_UCOS
#include "includes.h" //ucos 使用
#endif
//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
#endif
/*使用microLib的方法*/
/*
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (uint8_t) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {}
return ch;
}
int GetKey (void) {
while (!(USART1->SR & USART_FLAG_RXNE));
return ((int)(USART1->DR & 0x1FF));
}
*/
#if EN_USART1_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0; //接收状态标记
//初始化IO 串口1
//bound:波特率
void uart_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
USART_DeInit(USART1); //复位串口1
//USART1_TX PA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9
//USART1_RX PA.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
USART_Cmd(USART1, ENABLE); //使能串口
}
int comdata,i;
uint8_t RxBuffer1[6];
u8 RxState;
u8 RxFlag1,com_data;
u8 CX,RX;//接收的数据
void USART1_IRQHandler(void) //串口1中断服务程序
{
#ifdef OS_TICKS_PER_SEC //如果时钟节拍数定义了,说明要使用ucosII了.
OSIntEnter();
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
com_data = USART_ReceiveData(USART1);
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除中断标志
if(RxState==0&&com_data==0X55) //[帧头
{
RxState=1;
RxBuffer1[i++]=com_data;
}
else if(RxState==1)
{
RxBuffer1[i++]=com_data;
if(RxBuffer1[3]== 0XFF&&RxBuffer1[4]== 0XFF&&RxBuffer1[5]== 0XFF) //帧尾] //RxBuffer1接受满了,接收数据结束
{
RxFlag1=1;
CX=RxBuffer1[1];
RX=RxBuffer1[2];
sjcl();
RxFlag1 = 0;
i= 0;
RxState = 0;
RxBuffer1[0]=0;
RxBuffer1[1]=0;
RxBuffer1[2]=0;
RxBuffer1[3]=0;
RxBuffer1[4]=0;
RxBuffer1[5]=0;
}
}
}
#ifdef OS_TICKS_PER_SEC //如果时钟节拍数定义了,说明要使用ucosII了.
OSIntExit();
#endif
}
#endif
void sjcl(void)
{
//电机1
if(CX==0X00&&RX==0X00)MOTOR1(35);
if(CX==0X00&&RX==0X01)MOTOR1(0);
if(CX==0X00&&RX==0X02)MOTOR1(20);
if(CX==0X00&&RX==0X03)MOTOR1(50);
if(CX==0X00&&RX==0X04)MOTOR1(90);
//电机2
if(CX==0X01&&RX==0X00)MOTOR2(35);
if(CX==0X01&&RX==0X01)MOTOR2(0);
if(CX==0X01&&RX==0X02)MOTOR2(20);
if(CX==0X01&&RX==0X03)MOTOR2(50);
if(CX==0X01&&RX==0X04)MOTOR2(90);
//电机3
if(CX==0X02&&RX==0X00)MOTOR3(35);
if(CX==0X02&&RX==0X01)MOTOR3(0);
if(CX==0X02&&RX==0X02)MOTOR3(20);
if(CX==0X02&&RX==0X03)MOTOR3(50);
if(CX==0X02&&RX==0X04)MOTOR3(90);
//电机4
if(CX==0X03&&RX==0X00)MOTOR4(35);
if(CX==0X03&&RX==0X01)MOTOR4(0);
if(CX==0X03&&RX==0X02)MOTOR4(20);
if(CX==0X03&&RX==0X03)MOTOR4(50);
if(CX==0X03&&RX==0X04)MOTOR4(90);
//水泵
if(CX==0X04&&RX==0X00)RELAY_1(1);
if(CX==0X04&&RX==0X01)RELAY_1(0);
//灯泡
if(CX==0X05&&RX==0X00)RELAY_2(1);
if(CX==0X05&&RX==0X01)RELAY_2(0);
}
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "sys.h"
#define USART_REC_LEN 200 //定义最大接收字节数 200
#define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收
extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART_RX_STA; //接收状态标记
//如果想串口中断接收,请不要注释以下宏定义
void uart_init(u32 bound);
#endif