1 体征数据采集
需求:获取奶牛记步信息
三轴加速度测量:加速度测量计反应的加速向量与当前的受力方向是相反,单位为g
陀螺仪,是用来测量角速度的,单位为度每秒(deg/s) 2000deg/s 相当于1秒钟多少转
1.1 原理图
IIC的地址最后一1位
一键还原原理图d1、d2连接在核心板底座的con1和con2
同时,这两个引脚pb7、8可以直接使用IIC
1.2 驱动流程
陀螺仪测量范围是+-2000,加速度测量范围是+-2G,读取初始值是为了便于校准。每次读取到xyz要减去这个值
获取两个字节数据
1.3 修改cubmx工程
I2C使能 pb7和pb8引脚配置
IIC标准工程
建立sensor文件夹,用于放置传感器相关文件
查看芯片手册
采样频率参考MPU-6050寄存器映射
1.4 修改工程代码
使用i2c的阅读函数HAL_I2C_Mem_Read()、write
#include "mpu6050.h"
#include "string.h"
#include "stdio.h"
#include "i2c.h"
int16_t Accx,Accy,Accz;
//**********************************//
//函数名称: InitMpu6050
//函数描述: 初始化MPU6050
//函数参数: 无
//返回值: 无
//*******************************//
void InitMpu6050(void)
{
uint8_t WriteCmd = 0;
//解除休眠状态
WriteCmd = 0x00;
HAL_I2C_Mem_Write(&hi2c1, ADDRESS_Write, PWR_MGMT_1, I2C_MEMADD_SIZE_8BIT, &WriteCmd, 1, 0x10);
//时钟速率0x06(1Khz)陀螺仪采样率0x07(125Hz)
WriteCmd = 0x07;
HAL_I2C_Mem_Write(&hi2c1, ADDRESS_Write, SMPLRT_DIV, I2C_MEMADD_SIZE_8BIT, &WriteCmd, 1, 0x10);
WriteCmd = 0x06;
HAL_I2C_Mem_Write(&hi2c1, ADDRESS_Write, CONFIG, I2C_MEMADD_SIZE_8BIT, &WriteCmd, 1, 0x10);
//不自检,2000deg/s
WriteCmd = 0x18;
HAL_I2C_Mem_Write(&hi2c1, ADDRESS_Write, GYRO_CONFIG, I2C_MEMADD_SIZE_8BIT, &WriteCmd, 1, 0x10);
//(不自检,2G,5Hz)
WriteCmd = 0x01;
HAL_I2C_Mem_Write(&hi2c1, ADDRESS_Write, ACCEL_CONFIG, I2C_MEMADD_SIZE_8BIT, &WriteCmd, 1, 0x10);
HAL_Delay(10);
mpu6050_verify(&Accx, &Accy, &Accz); //读取第一次的值
}
//**********************************//
//函数名称: mpu6050_verify
//函数描述: MPU6050校验
//函数参数: int16_t *x, int16_t *y, int16_t *z
//返回值: 无
//*******************************//
void mpu6050_verify(int16_t *x, int16_t *y, int16_t *z)
{
uint8_t ReadBuffer[10] = {0};
HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_XOUT_L, I2C_MEMADD_SIZE_8BIT,&ReadBuffer[0],1, 0x10);
HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_XOUT_H, I2C_MEMADD_SIZE_8BIT,&ReadBuffer[1],1, 0x10);
*x = (ReadBuffer[1]<<8)+ReadBuffer[0] ;
HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_YOUT_L, I2C_MEMADD_SIZE_8BIT,&ReadBuffer[0],1, 0x10);
HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_YOUT_H, I2C_MEMADD_SIZE_8BIT,&ReadBuffer[1],1, 0x10);
*y = (ReadBuffer[1]<<8)+ReadBuffer[0] ;
HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_ZOUT_L, I2C_MEMADD_SIZE_8BIT,&ReadBuffer[0],1, 0x10);
HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_ZOUT_H, I2C_MEMADD_SIZE_8BIT,&ReadBuffer[1],1, 0x10);
*z = (ReadBuffer[1]<<8)+ReadBuffer[0] ;
}
//**********************************//
//函数名称: mpu6050_ReadData
//函数描述: MPU6060获取三轴数据
//函数参数: int16_t *x, int16_t *y, int16_t *z
//返回值: 无
//*******************************//
void mpu6050_ReadData(float *Mx, float *My, float *Mz)
{
int16_t x,y,z;
uint8_t ReadBuffer[10] = {0};
HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_XOUT_L, I2C_MEMADD_SIZE_8BIT,&ReadBuffer[0],1, 0x10);
HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_XOUT_H, I2C_MEMADD_SIZE_8BIT,&ReadBuffer[1],1, 0x10);
x = (ReadBuffer[1]<<8)+ReadBuffer[0] ;
x -= Accx;
*Mx = ((float)x)/16384;
HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_YOUT_L, I2C_MEMADD_SIZE_8BIT,&ReadBuffer[0],1, 0x10);
HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_YOUT_H, I2C_MEMADD_SIZE_8BIT,&ReadBuffer[1],1, 0x10);
y = (ReadBuffer[1]<<8)+ReadBuffer[0] ;
y -= Accy;
*My = ((float)y)/16384;
HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_ZOUT_L, I2C_MEMADD_SIZE_8BIT,&ReadBuffer[0],1, 0x10);
HAL_I2C_Mem_Read(&hi2c1, ADDRESS_Read, ACCEL_ZOUT_H, I2C_MEMADD_SIZE_8BIT,&ReadBuffer[1],1, 0x10);
z = (ReadBuffer[1]<<8)+ReadBuffer[0] ;
z -= Accz;
*Mz = ((float)z)/16384;
}
三轴数据读取,减去初始值校准
主程序中定义全局变量的xyz坐标
初始化I2C
初始化mpu6050
while(1)之前又写了一个while(1)
2 饲养环境采集
lora中集成温湿度传感器
2.1 原理图
D2连接到核心板con2
D2就是pb8
2.2 驱动分析
获取数据。
如果继续拉高就是70us说明时1,否则是0.
读取5个字节,获取稳定数据、湿度数据和校验码
2.3 修改工程代码
dh11.c
#include "stdint.h"
#include "tim.h"
#include "gpio.h"
#include "dht11.h"
#include "delay.h"
//温湿度定义
uint8_t ucharT_data_H=0,ucharT_data_L=0,ucharRH_data_H=0,ucharRH_data_L=0,ucharcheckdata=0;
void DHT11_TEST(void) //温湿传感启动
{
uint8_t ucharT_data_H_temp,ucharT_data_L_temp,ucharRH_data_H_humidity,ucharRH_data_L_humidity,ucharcheckdata_temp;
uint8_t ucharFLAG = 0,uchartemp=0;
uint8_t ucharcomdata;
uint8_t i;
{
D2_OUT_GPIO_Init(); //根据时序图配置为输出模式,拉低等待18毫秒
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
HAL_Delay_ms(18);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET); //拉高,配置为输入模式,等待40us
D2_IN_GPIO_Init();
HAL_Delay_10us(4);
}
if(!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8)) //如果响应信号是低电平 ,是否应答____
{
ucharFLAG=2; //无符号char型,超时保护,最多255,再+到0,如果=1设置为超时判断
while((!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8))&&ucharFLAG++); //__--80us等待拉高
ucharFLAG=2;
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8)&&ucharFLAG++); //--__80us等待拉低
for(i=0;i<8;i++) //读取数据
{
ucharFLAG=2;
while((!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8))&&ucharFLAG++); //判断是否拉高
HAL_Delay_10us(3); //如果拉高延时30us等待磐石是否拉低
uchartemp=0;
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8))uchartemp=1; //如果还是高,代表1,否则代表0
ucharFLAG=2;
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8)&&ucharFLAG++); //判断是否拉低,或者超时
if(ucharFLAG==1)break; //无符号char型,超时保护,最多255,再+到0,如果=1设置为超时判断
ucharcomdata<<=1; //左移1位
ucharcomdata|=uchartemp;
}
ucharRH_data_H_humidity = ucharcomdata; //赋值给湿度高8位
for(i=0;i<8;i++)
{
ucharFLAG=2;
while((!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8))&&ucharFLAG++);
HAL_Delay_10us(3);
uchartemp=0;
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8))uchartemp=1;
ucharFLAG=2;
while(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8)&&ucharFLAG++);
if(ucharFLAG==1)break;
ucharcomdata<<=1;
ucharcomdata|=uchartemp;
}
ucharRH_data_L_humidity = ucharcomdata; //赋值给湿度低8位
for(i=0;i<8;i++)
{
ucharFLAG=2;
while((!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8))&&ucharFLAG++);
HAL_Delay_10us(3);
uchartemp=0;
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8))uchartemp=1;
ucharFLAG=2;
while((HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8))&&ucharFLAG++);
if(ucharFLAG==1)break;
ucharcomdata<<=1;
ucharcomdata|=uchartemp;
}
ucharT_data_H_temp = ucharcomdata; //赋值给温度高8位
for(i=0;i<8;i++)
{
ucharFLAG=2;
while((!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8))&&ucharFLAG++);
HAL_Delay_10us(3);
uchartemp=0;
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8))uchartemp=1;
ucharFLAG=2;
while((HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8))&&ucharFLAG++);
if(ucharFLAG==1)break;
ucharcomdata<<=1;
ucharcomdata|=uchartemp;
}
ucharT_data_L_temp = ucharcomdata; //赋值给温度低8位
for(i=0;i<8;i++)
{
ucharFLAG=2;
while((!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8))&&ucharFLAG++);
HAL_Delay_10us(3);
uchartemp=0;
if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8))uchartemp=1;
ucharFLAG=2;
while((HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_8))&&ucharFLAG++);
if(ucharFLAG==1)break;
ucharcomdata<<=1;
ucharcomdata|=uchartemp;
}
ucharcheckdata_temp = ucharcomdata; //读取校验和
// humiture=1;
uchartemp=(ucharT_data_H_temp+ucharT_data_L_temp+ucharRH_data_H_humidity+ucharRH_data_L_humidity);
if(uchartemp==ucharcheckdata_temp) //判断校验和是否和读取的数据相同
{
ucharT_data_H = ucharT_data_H_temp; //进去赋值
ucharT_data_L = ucharT_data_L_temp;
ucharRH_data_H = ucharRH_data_H_humidity;
ucharRH_data_L = ucharRH_data_L_humidity;
ucharcheckdata = ucharcheckdata_temp;
}
}
else //没用成功读取,返回0
{
ucharT_data_H = 0;
ucharT_data_L = 0;
ucharRH_data_H = 0;
ucharRH_data_L = 0;
}
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); //重新调用systick的config,因为用到的延时毫秒和微妙都是systick,用完后要恢复
}
delay.c
#include "stm32f0xx_hal.h"
#include "delay.h"
/**
* @}
*/
void HAL_Delay_10us(__IO uint32_t Delay)
{
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
uint32_t temp;
uint8_t fac_us=60;
SysTick->LOAD=Delay*fac_us; //时间加载
SysTick->VAL=0x00; //清空计数器
SysTick->CTRL=0x01 ; //开始倒数
do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(1<<16)));//等待时间到达
SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
/**
* @}
*/
void HAL_Delay_ms(__IO uint32_t Delay)
{
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
uint32_t temp;
uint16_t fac_ms=6000;
SysTick->LOAD=Delay*fac_ms; //时间加载
SysTick->VAL=0x00; //清空计数器
SysTick->CTRL=0x01 ; //开始倒数
do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(1<<16)));//等待时间到达
SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
/**
* @}
*/
void HAL_Delay_us(__IO uint32_t Delay)
{
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
uint32_t temp;
uint8_t fac_us=6;
SysTick->LOAD=Delay*fac_us; //时间加载
SysTick->VAL=0x00; //清空计数器
SysTick->CTRL=0x01 ; //开始倒数
do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(1<<16)));//等待时间到达
SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
3 饲养环境控制
通过5v 二次回路AC驱动380风扇。试验里面采用了5v微型风扇
3.1 修改工程代码
gpio D1初始化
#include "gpio.h"
#include "fan.h"
#include <stdbool.h>
static uint8_t FanStaus = false;
//**********************************//
//函数名称: FanOn
//函数描述: 开启风扇
//函数参数: 无
//返回值: 无
//*******************************//
void FanOn(void)
{
HAL_GPIO_WritePin( FAN_GPIO_PORT, FAN_PIN, FAN_ON );
FanStaus = true;
}
//**********************************//
//函数名称: FanOff
//函数描述: 关闭风扇
//函数参数: 无
//返回值: 无
//*******************************//
void FanOff(void)
{
HAL_GPIO_WritePin( FAN_GPIO_PORT, FAN_PIN, FAN_OFF );
FanStaus = false;
}
//**********************************//
//函数名称: FanReadStaus
//函数描述: 读取风扇状态
//函数参数: 无
//返回值: 无
//*******************************//
uint8_t FanReadStaus( void )
{
return FanStaus;
}
主程序
SLCD_SHOW
4 项目集成开发
定时采集上传数据
修改RTC文件
因为IIC,重新使用了cubmx,把IIC初始化更改了,要重新恢复
修改数据处理任务
传感器定时上传函数
把之前rtc文件复制过来
上传节点传感器函数,可以通过main函数查找,因为开发了3个设备的传感器,要进行区分。之前放在main函数的while1中
根据协议文件,修改数据包
修改上传代码
//**********************************//
//函数名称: SendSensorDataUP
//函数描述: 上传节点传感器数据
//函数参数: 无
//返回值: 无
//*******************************//
void SendSensorDataUP(void)
{
printf("SendSensorDataUP\n");
//传感器类型6050
#if defined(MPU6050)
mpu6050_ReadData(&Mx,&My,&Mz);
printf("Mx = %.3f\n",Mx);
printf("My = %3f\n",My);
printf("Mz = %3f\n",Mz);
DataPacke_t.netmsgHead = 'N';
DataPacke_t.netPanid[0] = HI_UINT16(PAN_ID);
DataPacke_t.netPanid[1] = LO_UINT16(PAN_ID);
DataPacke_t.msgHead = 0x21;
DataPacke_t.dataLength = 0x08; //不含包头
DataPacke_t.dataType = 0x00;
DataPacke_t.deviceAddr[0] = HI_UINT16(ADDR);
DataPacke_t.deviceAddr[1] = LO_UINT16(ADDR);
DataPacke_t.sensorType = 0x3;
DataPacke_t.buff[0] = int8_t(Mx*10) //-127 128
DataPacke_t.buff[1] = int8_t(My*10)
DataPacke_t.buff[2] = int8_t(Mz*10)
//校验码
DataPacke_t.crcCheck = crc8((uint8_t *)&DataPacke_t,DataPacke_t.dataLength + 4);
//发送数据包
Radio->SetTxPacket((uint8_t *)&DataPacke_t, DataPacke_t.dataLength + 5);
//传感器类型dht11
#if defined(DHT11)
DHT11_TEST();
printf("TEMP = %d\n",ucharT_data_H);
printf("HUM = %d\n",ucharRH_data_H);
DataPacke_t.netmsgHead = 'N';
DataPacke_t.netPanid[0] = HI_UINT16(PAN_ID);
DataPacke_t.netPanid[1] = LO_UINT16(PAN_ID);
DataPacke_t.msgHead = 0x21;
DataPacke_t.dataLength = 0x07; //不含包头
DataPacke_t.dataType = 0x00;
DataPacke_t.deviceAddr[0] = HI_UINT16(ADDR);
DataPacke_t.deviceAddr[1] = LO_UINT16(ADDR);
DataPacke_t.sensorType = 0x1;
DataPacke_t.buff[0] = int8_t(ucharT_data_H) //-127 128
DataPacke_t.buff[1] = int8_t(ucharRH_data_H)
//校验码
DataPacke_t.crcCheck = crc8((uint8_t *)&DataPacke_t,DataPacke_t.dataLength + 4);
//发送数据包
Radio->SetTxPacket((uint8_t *)&DataPacke_t, DataPacke_t.dataLength + 5);
//传感器类型FAN
#if defined(FAN)
FanStaus = FanReadStaus();
DataPacke_t.netmsgHead = 'N';
DataPacke_t.netPanid[0] = HI_UINT16(PAN_ID);
DataPacke_t.netPanid[1] = LO_UINT16(PAN_ID);
DataPacke_t.msgHead = 0x21;
DataPacke_t.dataLength = 0x06; //不含包头
DataPacke_t.dataType = 0x01;
DataPacke_t.deviceAddr[0] = HI_UINT16(ADDR);
DataPacke_t.deviceAddr[1] = LO_UINT16(ADDR);
DataPacke_t.sensorType = 0x3;
DataPacke_t.buff[0] = int8_t(FanStaus)
//校验码
DataPacke_t.crcCheck = crc8((uint8_t *)&DataPacke_t,DataPacke_t.dataLength + 4);
//发送数据包
Radio->SetTxPacket((uint8_t *)&DataPacke_t, DataPacke_t.dataLength + 5);
#endif
}
修改解析代码
//**********************************//
//
//函数名称: SlaveProtocolAnalysis
//
//函数描述: 从机协议解析
//
//函数参数: uint8_t *buff,uint8_t len
//
//返回值: uint8_t
//
//*******************************//
uint8_t SlaveProtocolAnalysis(uint8_t *buff,uint8_t len)
{
uint8_t Crc8Data;
printf("SlaveProtocolAnalysis\n");
for (int i = 0; i < len; i++)
{
printf("0x%x ",buff[i]);
}
printf("\n");
if (buff[0] == NETDATA)
{
if (buff[1] == HI_UINT16(PAN_ID) && buff[2] == LO_UINT16(PAN_ID))
{
Crc8Data = crc8(&buff[0], len - 1);
if (Crc8Data != buff[len - 1])
{
memset(buff, 0, len);
return 0;
}
if (buff[3] == 0x21)
{
printf("Slave_NETDATA\n");
if( buff[5] == 0x01)
{
if(buff[6] == HI_UINT16(ADDR) && buff[7] == LO_UINT16(ADDR))
{
if(buff[8] == 0x03)
{
#if defined(FAN)
if(buff[9] == true)
{
FanON();
}
else
{
FanOff();
}
#endif
}
}
}
}
return 0;
}
}
else if((buff[0] == 0x3C) && (buff[2] == 'A'))
{
if (DataCrcVerify(buff, len) == 0)
{
return 0;
}
if (buff[3] == HI_UINT16(PAN_ID) && buff[4] == LO_UINT16(PAN_ID))
{
if (buff[5] == jionPacke_t.deviceAddr[0] && buff[6] == jionPacke_t.deviceAddr[1])
{
slaveNativeInfo_t.deviceId = buff[7];
printf("Slave_ACK\n");
return 0xFF;
}
}
}
else if((buff[0] == 0x3C) && (buff[2] == 'T'))
{
if (DataCrcVerify(buff, len) == 0)
{
return 0;
}
if (buff[3] == HI_UINT16(PAN_ID) && buff[4] == LO_UINT16(PAN_ID))
{
uint32_t alarmTime = 0;
startUpTimeHours = buff[5];
startUpTimeMinute = buff[6];
startUpTimeSeconds = buff[7];
startUpTimeSubSeconds = buff[8] <<8 | buff[9];
printf("Slave_CLOCK\n");
printf("H:%d,M:%d,S:%d,SUB:%d\n", startUpTimeHours, startUpTimeMinute, startUpTimeSeconds, startUpTimeSubSeconds);
alarmTime = ((DataUpTimeHours * 60 + DataUpTimeMinute) * 60
+ DataUpTimeSeconds) * 1000 + (DataUpTimeSubSeconds / 2) + DataUpTime;
GetTimeHMS(alarmTime, &DataUpTimeHours, &DataUpTimeMinute, &DataUpTimeSeconds, &DataUpTimeSubSeconds);
printf("DataUpTime->H:%d,M:%d,S:%d,SUB:%d\n", DataUpTimeHours, DataUpTimeMinute, DataUpTimeSeconds, DataUpTimeSubSeconds);
//使能RTC
MX_RTC_Init();
return 0xFF;
}
}
return 1;
}
CRC借用工具