【Lora智慧农业系统】让农民伯伯轻松坐等收割!

一、概述

​ 随着智能化的普及,利用物联网等信息技术改造传统农业,对农业生产要素进行数字化设计、智能化控制也快速发展了起来。为了提高农业的产量以及改善农业生态环境,提高生产经营效率,方便人们日常生活,我们设计了一种更加自动化、智能化、人性化的智慧农业方案。

1、功能

​ (1)支持APP进行远程控制设备的运行;

​ (2)支持控制屏进行本地控制设备的运行;

​ (3)可以实时远程观看所需数据情况。

2、硬件框图

image-20210821164927855

3、软件框图

image-20210824203335908

二、硬件方案介绍

1、主控部分

​ 发送部分采用GD32E230C8T6的一款单片机,接收部分采用的是ST的一款NUCLEO-L476RGDE开发板。

发送部分:

(1)原理图(点击下载)

image-20210824141734196

(2)PCB(点击下载)

image-20210824161328551

接收部分:

(1)原理图(点击下载)

注意:下面原理图只截取部分,完整的原理图请参照上面的下载链接。

image-20210823173833493

(2)PCB(点击下载)

image-20210823173717514

2、传感器部分

(1)照度检测(点击下载)

​ 光照度检测我们选取一个 BH1750照度检测模块来实现。BH1750 照度检测模块搭载一个BH1750FVI,是I2C总线接口的数字环境光传感器IC。可以准确读取1-65535XL的环境照度。

image-20210308163608700

原理图如下:

image.png

管脚介绍

名称VCCGNDSCLSDAADDR
功能描述3~5V供电参考地IIC时钟线IIC数据线地址线

(2)温湿度传感器

​ 温湿度检测我们选取涂鸦的SHT30模块来实现。涂鸦三明治温湿度传感功能板为三明治开发板的应用部分,方便开发者快速实现温湿度硬件产品原型的一款开发板。功能板主要包含一颗 SENSIRION 温湿度传感器 SHT30-DIS,通过 I2C 协议进行通信,I2C时钟频率最高支持1MHz。

image-20210823103536447

关键器件介绍

器件说明
U1(SHT30-DIS)SENSIRION 温湿度传感器,工作电压 2.4~5.5V,湿度精度 ±2%RH,温度精度 ±0.3℃,封装 8 脚 DFN

涂鸦三明治温湿度传感功能板需要用到的管脚介绍

I/O说明
VCC电源供电脚
GND电源参考地
SCLI2C时钟信号
SDAI2C数据信号
INT告警信号,预留

电源技术要求

  • 电源供电电压参照传感器工作电压范围:2.4~5.5V

  • 非测量状态典型电流:0.2uA

  • 低功耗连续测量模式典型电流:800uA

    (1)原理图

    ​ 涂鸦三明治温湿度传感功能板的原理图如下所示:

温湿度传感功能板

(2)PCB图

​ 涂鸦三明治温湿度传感功能板的 PCB 如下图所示:

温湿度传感功能板

注意事项

  • 功能板为应用部分,需配合控制板与电源板使用。
  • 电源接口不要触碰 I/O 管脚,避免击穿模块对应 I/O 口。
  • 传感器本体附着灰尘与油污等会导致测量精度下降。
  • 传感器本体不能与清洁剂接触,例如洗板水。
  • 不能使用会释放化学分子的材料包装,否则可能受污染导致数据偏移或完全损坏。

3、无线通信部分

(1)LORA通信(发送部分)

​ LORA通信发送部分采用的是WPG公司的LLCC68的芯片。该芯片和SX1268管脚兼容。此次设计没有使用开关芯片来进行发送与接收模式的切换。直接使用双天线,采用半双工的通信方式。

image-20210823105202586

(2)LORA通信(接收部分)

​ LORA通信接收部分采用的是WPG公司的SX1268模块。image-20210823105948905

注意:SX1268和LLCC68管脚兼容,但参数设置有些区别。SX1268扩频因子可以支持到SF12,但LLCC68只能到SF11。所以在程序设计的时候要注意了。

SX1268参数如下图:

image-20210823111328952

LLCC68参数如下图:

image-20210823111733813

(3)WB3S通信

​ WB3S是由涂鸦智能开发的一款低功耗嵌入式Wi-Fi+蓝牙BLE双协议云模组。它由一个高集成度的无线射频芯片BK7231T和少量外围器件构成,内置了Wi-Fi网络协议栈和丰富的库函数。MCU通过串口和WB3S进行通信,采用透传的模式。

4、控制屏部分

​ 显示控制部分采用的是迪文的4.3寸串口屏。

​ 正面图:

image-20210823113755984

​ 背面图:

image-20210823113205652
​ 接口图:

image-20210823113311517

此次设计中界面设计的主界面效果如下图:

image-20210823114244754

MCU和显示屏通过串口通信,来实现控制和显示。

三、产品创建

  • 进入 涂鸦IoT平台,点击创建产品,选择标准类目->电工->开关。(当时为了测试用,所以选择一个标准类目,也可以在平台上其他品类中去创建也是可以的)
    image-20210823115534415
  • 选择自定义方案,输入产品名称,选择通讯协议为Wi-Fi+蓝牙,点击创建产品
  • 根据要实现的设备功能,创建好DP功能点。
    image-20210823115756972
  • 设定完功能点后,下一步点击设备面板,选择App的面板样式。推荐选择自由配置面板,比较直观,方便灵活。

​ 至此,产品的创建基本完成,可以正式开始嵌入式软件部分的开发。

四、软件方案介绍

1、发送部分(即GD32采集传感器数据通过LORA发送出去)

(1)程序设计入口

打开demo例程,其中GD32_LORA_TRANSMIT文件夹内就是demo的应用代码。应用代码结构如下:

├── Application
│   ├── main.c
│   ├── gd32e23x_it.c
│   ├── systick.c
│   ├── gd32e23x_it.h
│   ├── systick.h
│   ├── gd32e23x_libopt.h
├── GD32E23x_Firmware_Library
│   ├── CMSIS├── Include│   ├──gd32e23x.h│   ├──system_gd32e23x.h├── Source│   ├──startup_gd32e23x.s│   ├──system_gd32e23x.h        
│   ├── GD32E23x_standard_peripheral├── Include├── Source
├──User
│   ├── BH1750.c
│   ├── BH1750.h
│   ├──delay.c
│   ├──delay.h
│   ├──sht3x.c
│   ├──sht3x.h
│   ├──soft_i2c.c
│   ├──soft_i2c.h
│   ├──SPI.c
│   ├──SPI.h
│   ├──sx126x_v01.c
│   ├──sx126x_v01.h
│   ├──usart.c
└──────usart.h 

(2)光照度传感器的驱动

​ 为了检测光照度,选用的传感器型号为BH1750,通过I2C协议与GD32进行通信,相关接口封装都在BH1750.c 文件中。模块具体使用流程如下:

调用Init_BH1750初始化模块:

//初始化BH1750,根据需要请参考pdf进行修改****
void Init_BH1750()
{   /*开启GPIOB的外设时钟*/ 
rcu_periph_clock_enable(RCU_GPIOB);   
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_6|GPIO_PIN_7); 
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6|GPIO_PIN_7); 	
Single_Write_BH1750(0x01);  
Delay_ms(180);    //延时180ms
}

调用mread连续读出BH1750内部数据:

//连续读出BH1750内部数据
void mread(void)
{   uchar i;	BH1750_Start();                        //起始信号BH1750_SendByte(SlaveAddress+1);       //发送设备地址+读信号for (i=0; i<3; i++)                     //连续读取6个地址数据,存储中BUF{BUF[i] = BH1750_RecvByte();          //BUF[0]存储0x32地址中的数据if (i == 3){BH1750_SendACK(1);                  //最后一个数据需要回NOACK}else{		BH1750_SendACK(0);                  //回应ACK}}BH1750_Stop();                        //停止信号Delay_ms(5);
}

调用read_BH1750获取光照强度值:

uint16_t read_BH1750(void)
{int dis_data;                        //变量	float temp1;float temp2;Single_Write_BH1750(0x01);   // power onSingle_Write_BH1750(0x10);   // H- resolution modeDelay_ms(180);            //延时180msmread();       //连续读出数据,存储在BUF中dis_data=BUF[0];dis_data=(dis_data<<8)+BUF[1]; //合成数据 temp1=dis_data/1.2;temp2=10*dis_data/1.2;	temp2=(int)temp2%10;	return (uint16_t)temp1;
}

(3)温湿度传感器的驱动

​ 为了测量温湿度,选取涂鸦的SHT30温湿度模块来实现。通过 I2C 协议与GD32进行通信,I2C时钟频率最高支持1MHz。

调用SHT3x_reset复位模块:

/**
* @brief   复位SHT3x
* @param   none
* @retval  none
*/
void SHT3x_reset(void)
{SHT3x_Send_Cmd(SOFT_RESET_CMD);delay_1ms(20);
}

调用SHT3x_Init初始化模块:

/* 描述:SHT3x初始化函数,并将其设置为周期测量模式* 参数:无* 返回值:初始化成功返回0,初始化失败返回1 */uint8_t SHT3x_Init(void){uint8_t ret;IIC_Init();IIC_Start();ret = SHT3x_Send_Cmd(MEDIUM_2_CMD);IIC_Stop();return ret;}

调用 SHT3x_Get_Humiture_periodic获取温湿度值:

/* 描述:温湿度数据获取函数,周期读取,注意,需要提前设置周期模式   
* 参数Tem_val:存储温度数据的指针, 温度单位为°C
* 参数Hum_val:存储湿度数据的指针, 温度单位为%
* 返回值:0-读取成功,1-读取失败
********************************************************************/
uint8_t SHT3x_Get_Humiture_periodic(double *Tem_val,double *Hum_val)
{uint8_t ret=0;uint8_t buff[6]={0};uint16_t tem,hum;double Temperature=0;double Humidity=0;IIC_Start();ret = SHT3x_Send_Cmd(READOUT_FOR_PERIODIC_MODE);	IIC_Start();ret = SHT3x_Recv_Data(6,buff);IIC_Stop();/* 校验温度数据和湿度数据是否接收正确 */if(CheckCrc8(buff, 0xFF) != buff[2] || CheckCrc8(&buff[3], 0xFF) != buff[5]){	printf("CRC_ERROR,ret = 0x%x\r\n",ret);return 1;}/* 转换温度数据 */tem = (((uint16_t)buff[0]<<8) | buff[1]);//温度数据拼接Temperature= (175.0*(double)tem/65535.0-45.0) ;	// T = -45 + 175 * tem / (2^16-1)/* 转换湿度数据 */hum = (((uint16_t)buff[3]<<8) | buff[4]);//湿度数据拼接Humidity= (100.0*(double)hum/65535.0);			// RH = hum*100 / (2^16-1)/* 过滤错误数据 */if((Temperature>=-20)&&(Temperature<=125)&&(Humidity>=0)&&(Humidity<=100)){*Tem_val = Temperature;*Hum_val = Humidity;return 0;}elsereturn 1;
}

(4)LORA芯片驱动

​ 为了远距离,低功耗的传输数据,采用的是WPG公司的LLCC68的芯片。通过SPI 协议与GD32进行通信。采用半双工的通信方式。

调用RadioInit初始化模块:

//RADIO 层 ///
void RadioInit(void)
{//RadioEvents = events;//这里进行了函数的初始化
#ifdef USE_TCXO
printf("USE TCXO\n");
#else
printf("USE CRYSTAL\n");
#endifSX126xInit();中断的回调函后续在其他地方去定义SX126xSetStandby( STDBY_RC );SX126xSetRegulatorMode( USE_DCDC);//USE_LDO//USE_DCDCSX126xSetBufferBaseAddress( 0x00, 0x00 );SX126xSetTxParams( 0, RADIO_RAMP_200_US );//DIO_0的中断MASK全部打开,在RadioSend()会再继续细分中断SX126xSetDioIrqParams( IRQ_RADIO_ALL, IRQ_RADIO_ALL, IRQ_RADIO_NONE, IRQ_RADIO_NONE );
}

调用 SX126xOnDio1Irq进行数据处理:

//DIO1的中断函数
void SX126xOnDio1Irq(void)
{uint16_t irqRegs = SX126xGetIrqStatus( );SX126xClearIrqStatus( IRQ_RADIO_ALL );//这里清掉中断标志//发送结束if( ( irqRegs & IRQ_TX_DONE ) == IRQ_TX_DONE ){TXDone=true;gpio_bit_toggle(LED_GPIO_Port, LED_Pin);OnTxDone();}//在SX126xSetTx()设置了一个超时时间 可以检测改功能 --okif( ( irqRegs & IRQ_RX_TX_TIMEOUT ) == IRQ_RX_TX_TIMEOUT ){TimeOutFlag=true;printf(" RX/TX timeout\n");}if( ( irqRegs & IRQ_RX_DONE ) == IRQ_RX_DONE ){SX126xGetPayload( RadioRxPayload, &RadioRxPacketSize , 255 );SX126xGetPacketStatus( &RadioPktStatus );gpio_bit_toggle(LED_GPIO_Port, LED_Pin);OnRxDone();RXDoneFlag=true;}if( ( irqRegs & IRQ_CRC_ERROR ) == IRQ_CRC_ERROR ){printf("CRC fail\n");CRCFail=true;}if( ( irqRegs & IRQ_CAD_DONE ) == IRQ_CAD_DONE ){if ( ( irqRegs & IRQ_CAD_ACTIVITY_DETECTED ) == IRQ_CAD_ACTIVITY_DETECTED ) {//printf("IRQ_CAD_ACTIVITY_DETECTED\n");	//CadDetect=true;}      }if( ( irqRegs & IRQ_PREAMBLE_DETECTED ) == IRQ_PREAMBLE_DETECTED ){__NOP( );}if( ( irqRegs & IRQ_SYNCWORD_VALID ) == IRQ_SYNCWORD_VALID ){__NOP( );}if( ( irqRegs & IRQ_HEADER_VALID ) == IRQ_HEADER_VALID ){__NOP( );}
}

(5)主程序设计

#define LORA_MODE	1
#define FSK_MODE  0
#define TRANSMITTER 1
#define RECEIVER   0
int main(void)
{uint8_t i=0;uint16_t  light;double Tem_val,Hum_val;bool DetectTruetable[100]={0};//CAD成功的分布bool RXTruetable[100]={0};//CAD后能接收正确的分布uint8_t CadDetectedTime=0;//检测到的cad的次数uint8_t RxCorrectTime=0;//RX 接收正确次数uint8_t TxTime=0;		//TX 次数int random_number=0;RadioStatus_t RadioStatus;//连续发送的时候用uint8_t ModulationParam[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };uint8_t PacketParam[9] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };/* Configure the system clock */systick_config(); /* Initialize all configured peripherals */MX_GPIO_Init();rcu_config();gpio_config();spi_config();USART0_Init();USART1_Init();Init_BH1750();SHT3x_reset();if( 0 == SHT3x_Init())printf("SHT3x_Init OK \r\n");elseprintf("SHT3x_Init ERR \r\n");gpio_bit_toggle(LED_GPIO_Port, LED_Pin);Delay_ms(250);SX126xReset();i=SX126xReadRegister(REG_LR_CRCSEEDBASEADDR);if(i==0x1D){   printf("SPI SUCCESS!\n\r");}else{printf("SPI Fail! REG_LR_CRCSEEDBASEADDR=%x\n\r",i);}RadioInit();SX126xWriteRegister(0x889, SX126xReadRegister(0x889) & 0xfB);//SdCfg0 (0x889) sd_res (bit 2) = 0 printf("RadioInit Done!\n\r");
while (1){
#if (TRANSMITTER==1)while(1){ light =read_BH1750();/* 采集温湿度数据 */if(SHT3x_Get_Humiture_periodic(&Tem_val,&Hum_val) == 0){memcpy(Buffer,(double*)(&Tem_val),8);		memcpy(Buffer+8,(double*)(&Hum_val),8);}elseprintf("Get_Humiture ERR\r\n");memcpy(Buffer+16, (uint16_t*)&light, sizeof((uint16_t*)&light));RadioSend(Buffer ,18);printf("1=%d\n",read_BH1750());	while(TXDone==false && TimeOutFlag==false);//一直等待tx doneTXDone=false;TimeOutFlag=false;printf("TxTime=%d\n",TxTime);Delay_ms(1000); //1s//读取状态RadioStatus=SX126xGetStatus();printf("RadioStatus is(after TX_DONE) %d\n",(((RadioStatus.Value)>>4)&0x07));	}
#elif (RECEIVER==1) while(1){#if (RX_CONTINOUS==1)//开始接收RadioRx(0xFFFFFF);//50MS(0XC80)超时  0-单次接收 无超时printf("continous RX...\n");while(1);//连续接收
#endifRadioRx(2000);//50MS(0XC80)超时  0-单次接收 无超时while(RXDoneFlag==false && TimeOutFlag==false && CRCFail==false);if(RXDoneFlag==true || TimeOutFlag==true || CRCFail==true){if(CRCFail==false)	//CRC无错误{if(RXDoneFlag==true){printf("\n%d:RxCorrect-PING\n",RxCorrectTime);RxCorrectTime++;}}CRCFail=false;RXDoneFlag=false;TimeOutFlag=false;}}
#endif		}
}

本demo发送部分完整工程:[点此下载](Tuya-Community/tuya-iotos-embeded-mcu-demo-wifi-ble-GD32_LORA_TRANSMIT (github.com))

2、接收部分(即STM32收到LORA模块的数据进行处理控制)

(1)程序设计入口

打开demo例程,其中STM32_LORA_LCD_RECEIVE文件夹内就是demo的应用代码。应用代码结构如下:

├── Src
│   ├── main.c
│   ├── connect_wifi.c
│   ├── delay.c
│   ├── lcd.c
│   ├── myOS.c
│   ├── stm32l4xx_hal_msp.c
│   ├── stm32l4xx_it.c
│   ├── sx126x_v01.c
│   ├── system_stm32l4xx.c
│   ├── time.c
│   ├──usart.c
├── Inc
│   ├── main.h
│   ├── connect_wifi.h
│   ├── delay.h
│   ├── lcd.h
│   ├── myOS.h
│   ├── stm32l4xx_hal_conf.h
│   ├── stm32l4xx_it.h
│   ├── sx126x_v01.h
│   ├── time.h
│   ├── type.h
│   ├──usart.h
├── Drivers
│   ├── CMSIS├── Device│   ├──STM32L4xx├── DSP_Lib│   ├──Source├── Include├── Lib│   ├──ARM│   ├──GCC├── RTOS│   ├──Template
│   ├── STM32L4xx_HAL_Driver├── Inc├── Src
└── MCU_SDK├── mcu_api.c├── mcu_api.h├── protocol.c├── protocol.h├── system.c├── system.h└── wifi.h  

(2)LORA模块驱动

​ 采用的是WPG公司的SX1268模块。通过SPI 协议与STM32进行通信。采用半双工的通信方式。驱动同LLCC68,但二者参数设置有些差别。差别如下所示:

SX1268扩频因子可以支持到SF12,但LLCC68只能到SF11。为了适用这两款芯片,同时满足要求,此处扩频因子选择SF10。

#define LORA_BANDWIDTH                              1       // [0: 125 kHz,//	1: 250 kHz, 													//	2: 500k//	3 :20.83kHz//	4:31.25kHz//	5:62.5kHz4//6:41.67
#define LORA_SPREADING_FACTOR                       10      // [SF7..SF12]

(3)控制屏程序设计

​ STM32通过串口和控制屏进行通信,波特率115200。

界面设计

​ 首先采用PS软件做出自己需要的图片,然后保存成800*480分辨率的BMP图片格式。接着采用迪文的一款上位机软件进行显示和控制设计。

温湿度界面:

image-20210823163804336

image-20210824152538656

光照度界面:

image-20210824153113907

image-20210823164138158

节点控制界面:

image-20210823164537015

image-20210824152634111

控制屏界面设计完整工程:点此下载

驱动程序设计

调用WriteDataToLCD对控制屏写入数据:

/*******************************************************************************
** Function Name  :void WriteDataToLCD(uint16_t startAddress,uint16_t return_data_start_addr,uint16_t length)
** Description    : 数据写入触摸屏变量寄存器
** Input          : uint16_t startAddress,uint16_t return_data_start_addr,uint16_t length
** Output         : None
** Return         : None
** Attention		 	: 
*******************************************************************************/
void WriteDataToLCD(uint16_t startAddress,uint16_t return_data_start_addr,uint16_t length)
{/*命令的长度由帧头(2个字节)+数据长度(1个字节)+指令(1个字节)+起始地址(2个字节)+数据(长度为length)*/uint8_t i;usart1_txBuf[0]=0x5a;usart1_txBuf[1]=0xa5;usart1_txBuf[2]=length+3;usart1_txBuf[3]=0x82;usart1_txBuf[4]=(uint8_t)((startAddress>>8)&0xff);//起始地址usart1_txBuf[5]=(uint8_t)(startAddress&0XFF);//起始地址for(i=0;i<length;i++){usart1_txBuf[i+6]=((SEND_BUF[i+return_data_start_addr]));}HAL_UART_Transmit(&huart1, usart1_txBuf, length+6, 20);
}

调用ReadDataFromLCD读取控制屏数据:

/*******************************************************************************
** Function Name  :void ReadDataFromLCD(uint16_t startAddress,uint8_t readWordLength)
** Description    : 读变量存储器数据
** Input          : uint16_t startAddress,uint8_t readWordLength
** Output         : None
** Return         : None
** Attention		 	: 
*******************************************************************************/
void ReadDataFromLCD(uint16_t startAddress,uint16_t readWordLength)
{//命令的长度由帧头(2个字节)+数据长度(1个字节)+指令(1个字节)+起始地址(2个字节)+读取的字长度(1个字节)usart1_txBuf[0]=0x5a;usart1_txBuf[1]=0xa5;usart1_txBuf[2]=0x04;usart1_txBuf[3]=0x83;usart1_txBuf[4]=(uint8_t)((startAddress>>8)&0xff);//起始地址usart1_txBuf[5]=(uint8_t)(startAddress&0xff);//起始地址usart1_txBuf[6]=readWordLength;//读取长度HAL_UART_Transmit(&huart1, usart1_txBuf, 7 , 20);
}

调用void send_tz控制页面跳转:

/*******************************************************************************
** Function Name  :void send_tz(void))
** Description    : 跳转页面函数
** Input          : None
** Output         : None
** Return         : None
** Attention		 	: 
*******************************************************************************/
void send_tz(void)
{uint8_t i;usart1_txBuf[0]=0x5a;usart1_txBuf[1]=0xa5;usart1_txBuf[2]=0x07;usart1_txBuf[3]=0x82;usart1_txBuf[4]=0x00;usart1_txBuf[5]=0x84;usart1_txBuf[6]=0x5a;usart1_txBuf[7]=0x01;for(i=0;i<2;i++){usart1_txBuf[i+8]=((SEND_BUF[i]));}HAL_UART_Transmit(&huart1, usart1_txBuf, 10, 20);
}

(4)WB3S模组

​ STM32通过串口和WB3S进行通信,采用透传的模式。

调用wifi_protocol_init初始化模块串口协议:

/**
* @brief  协议串口初始化函数
* @param  Null
* @return Null
* @note   在MCU初始化代码中调用该函数
*/
void wifi_protocol_init(void)
{//#error " 请在main函数中添加wifi_protocol_init()完成wifi协议初始化,并删除该行"rx_buf_in = (unsigned char *)wifi_uart_rx_buf;rx_buf_out = (unsigned char *)wifi_uart_rx_buf;stop_update_flag = DISABLE;#ifndef WIFI_CONTROL_SELF_MODEwifi_work_state = WIFI_SATE_UNKNOW;
#endif
}

调用 wifi_uart_service对串口数据进行处理:

/**
* @brief  wifi串口数据处理服务
* @param  Null
* @return Null
* @note   在MCU主函数while循环中调用该函数
*/
void wifi_uart_service(void)
{//#error "请直接在main函数的while(1){}中添加wifi_uart_service(),调用该函数不要加任何条件判断,完成后删除该行" static unsigned short rx_in = 0;unsigned short offset = 0;unsigned short rx_value_len = 0;while((rx_in < sizeof(wifi_data_process_buf)) && with_data_rxbuff() > 0){wifi_data_process_buf[rx_in ++] = take_byte_rxbuff();}if(rx_in < PROTOCOL_HEAD)return;while((rx_in - offset) >= PROTOCOL_HEAD) {if(wifi_data_process_buf[offset + HEAD_FIRST] != FRAME_FIRST){offset ++;continue;}if(wifi_data_process_buf[offset + HEAD_SECOND] != FRAME_SECOND){offset ++;continue;}  if(wifi_data_process_buf[offset + PROTOCOL_VERSION] != MCU_RX_VER) {offset += 2;continue;}      rx_value_len = wifi_data_process_buf[offset + LENGTH_HIGH] * 0x100;rx_value_len += (wifi_data_process_buf[offset + LENGTH_LOW] + PROTOCOL_HEAD);if(rx_value_len > sizeof(wifi_data_process_buf) + PROTOCOL_HEAD){offset += 3;continue;}if((rx_in - offset) < rx_value_len) {break;}//数据接收完成if(get_check_sum((unsigned char *)wifi_data_process_buf + offset,rx_value_len - 1) != wifi_data_process_buf[offset +                rx_value_len - 1]){offset += 3;continue;}data_handle(offset);offset += rx_value_len;}//end whilerx_in -= offset;if(rx_in > 0) {my_memcpy((char *)wifi_data_process_buf, (const char *)wifi_data_process_buf + offset, rx_in);}
}

调用以下DP处理函数对控制屏和GPIO进行控制:

/*****************************************************************************
函数名称 : dp_download_switch_1_handle
功能描述 : 针对DPID_SWITCH_1的处理函数
输入参数 : value:数据源数据: length:数据长度
返回参数 : 成功返回:SUCCESS/失败返回:ERROR
使用说明 : 可下发可上报类型,需要在处理完数据后上报处理结果至app
*****************************************************************************/
static unsigned char dp_download_switch_1_handle(const unsigned char value[], unsigned short length)
{//示例:当前DP类型为BOOLunsigned char ret;//0:关/1:开unsigned char switch_1;switch_1 = mcu_get_dp_download_bool(value,length);if(switch_1 == 0){//开关关SEND_BUF[0]=0x00;SEND_BUF[1]=0x06; send_tz();SEND_BUF[0]=0x00;SEND_BUF[1]=0x00; WriteDataToLCD(0x1000,0,2);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET); }else {SEND_BUF[0]=0x00;SEND_BUF[1]=0x06; send_tz();SEND_BUF[0]=0x00;SEND_BUF[1]=0x01; WriteDataToLCD(0x1000,0,2);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET);//开关开}//处理完DP数据后应有反馈ret = mcu_dp_bool_update(DPID_SWITCH_1,switch_1);if(ret == SUCCESS)return SUCCESS;elsereturn ERROR;
}
/*****************************************************************************
函数名称 : dp_download_switch_2_handle
功能描述 : 针对DPID_SWITCH_2的处理函数
输入参数 : value:数据源数据: length:数据长度
返回参数 : 成功返回:SUCCESS/失败返回:ERROR
使用说明 : 可下发可上报类型,需要在处理完数据后上报处理结果至app
*****************************************************************************/
static unsigned char dp_download_switch_2_handle(const unsigned char value[], unsigned short length)
{//示例:当前DP类型为BOOLunsigned char ret;//0:关/1:开unsigned char switch_2;switch_2 = mcu_get_dp_download_bool(value,length);if(switch_2 == 0) {SEND_BUF[0]=0x00;SEND_BUF[1]=0x06; send_tz();SEND_BUF[0]=0x00;SEND_BUF[1]=0x00; WriteDataToLCD(0x1001,0,2);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET); //开关关}else {SEND_BUF[0]=0x00;SEND_BUF[1]=0x06; send_tz();SEND_BUF[0]=0x00;SEND_BUF[1]=0x01; WriteDataToLCD(0x1001,0,2);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET); //开关开}//处理完DP数据后应有反馈ret = mcu_dp_bool_update(DPID_SWITCH_2,switch_2);if(ret == SUCCESS)return SUCCESS;elsereturn ERROR;
}
/*****************************************************************************
函数名称 : dp_download_switch_3_handle
功能描述 : 针对DPID_SWITCH_3的处理函数
输入参数 : value:数据源数据: length:数据长度
返回参数 : 成功返回:SUCCESS/失败返回:ERROR
使用说明 : 可下发可上报类型,需要在处理完数据后上报处理结果至app
*****************************************************************************/
static unsigned char dp_download_switch_3_handle(const unsigned char value[], unsigned short length)
{//示例:当前DP类型为BOOLunsigned char ret;//0:关/1:开unsigned char switch_3;switch_3 = mcu_get_dp_download_bool(value,length);if(switch_3 == 0) {SEND_BUF[0]=0x00;SEND_BUF[1]=0x06; send_tz();SEND_BUF[0]=0x00;SEND_BUF[1]=0x00; WriteDataToLCD(0x1002,0,2);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET); //开关关}else {SEND_BUF[0]=0x00;SEND_BUF[1]=0x06; send_tz();SEND_BUF[0]=0x00;SEND_BUF[1]=0x01; WriteDataToLCD(0x1002,0,2);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_SET); //开关开}//处理完DP数据后应有反馈ret = mcu_dp_bool_update(DPID_SWITCH_3,switch_3);if(ret == SUCCESS)return SUCCESS;elsereturn ERROR;
}
/*****************************************************************************
函数名称 : dp_download_switch_4_handle
功能描述 : 针对DPID_SWITCH_4的处理函数
输入参数 : value:数据源数据: length:数据长度
返回参数 : 成功返回:SUCCESS/失败返回:ERROR
使用说明 : 可下发可上报类型,需要在处理完数据后上报处理结果至app
*****************************************************************************/
static unsigned char dp_download_switch_4_handle(const unsigned char value[], unsigned short length)
{//示例:当前DP类型为BOOLunsigned char ret;//0:关/1:开unsigned char switch_4;switch_4 = mcu_get_dp_download_bool(value,length);if(switch_4 == 0) {SEND_BUF[0]=0x00;SEND_BUF[1]=0x06; send_tz();SEND_BUF[0]=0x00;SEND_BUF[1]=0x00; WriteDataToLCD(0x1003,0,2);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET); //开关关}else {SEND_BUF[0]=0x00;SEND_BUF[1]=0x06; send_tz();SEND_BUF[0]=0x00;SEND_BUF[1]=0x01; WriteDataToLCD(0x1003,0,2);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET); //开关开}//处理完DP数据后应有反馈ret = mcu_dp_bool_update(DPID_SWITCH_4,switch_4);if(ret == SUCCESS)return SUCCESS;elsereturn ERROR;
}

(5)按键配网

调用Connect_Wifi进行配网设置,通过WB3S模组连接涂鸦云平台。

void Connect_Wifi(void)
{
if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(WIFI_KEY_GPIO_Port, WIFI_KEY_Pin)){delay_ms(10);if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(WIFI_KEY_GPIO_Port, WIFI_KEY_Pin)){mcu_set_wifi_mode(0);printf("begin connect wifi\r\n");}}switch(mcu_get_wifi_work_state()){case SMART_CONFIG_STATE:       printf("smart config\r\n");HAL_GPIO_TogglePin(WIFI_LED_GPIO_Port, WIFI_LED_Pin);delay_ms(250);break;case AP_STATE:        printf("AP config\r\n");HAL_GPIO_TogglePin(WIFI_LED_GPIO_Port, WIFI_LED_Pin);delay_ms(500);break;case WIFI_NOT_CONNECTED: printf("connect wifi\r\n");HAL_GPIO_WritePin(WIFI_LED_GPIO_Port, WIFI_LED_Pin, GPIO_PIN_SET);	 break;case WIFI_CONNECTED:printf("connect success\r\n");HAL_GPIO_WritePin(WIFI_LED_GPIO_Port, WIFI_LED_Pin, GPIO_PIN_SET);	 case WIFI_CONN_CLOUD:HAL_GPIO_WritePin(WIFI_LED_GPIO_Port, WIFI_LED_Pin, GPIO_PIN_SET);break;default:HAL_GPIO_WritePin(WIFI_LED_GPIO_Port, WIFI_LED_Pin, GPIO_PIN_RESET);	 printf ("connect fail\r\n");break;}
}

(6)系统管理函数接口设计

由于使用串口较多,防止出现串口数据传输过程中被干扰的情况出现,此处利用定时器3中断,写了一个系统管理函数。不同定时时间处理不同的任务。

//系统管理函数
void System_Management(void)
{static __IO uint8_t timer_50ms = 0U;static __IO uint8_t timer_500ms = 0U;static __IO uint8_t timer_1000ms = 0U;static __IO uint8_t timer_10s = 0U;system_running_timer++;	System_Run_2ms();		/*2ms task*/timer_50ms++;/*write if-else to aviod multiple task are running at same timeonly running 2ms task and one of 50ms, 500ms and 1s every 2ms.*/if(timer_50ms >= 25u){timer_50ms = 0u;Systen_Run_50ms();timer_500ms ++;}else if(timer_500ms >= 10u){timer_500ms = 0u;System_Run_500ms();timer_1000ms ++;}else if(timer_1000ms >= 2u){timer_1000ms = 0u;System_Run_1000ms();timer_10s ++;}else{}
}

调用System_Run_2ms和Systen_Run_50ms分别处理WiFi模组和LORA模块的数据。

/*2ms task
*/
void System_Run_2ms(void)
{system_running_timer += 2;  /*Record system running time*/	wifi_uart_service();//wifi串口数据处理服务Connect_Wifi(); //配网  
}/*50ms task
*/
void Systen_Run_50ms(void)
{ OnRxDone();
}

(7)主程序设计

#define LORA_MODE	1
#define FSK_MODE   0
#define TRANSMITTER    0
#define RECEIVER       1int main(void)
{uint8_t i=0;bool DetectTruetable[100]={0};//CAD成功的分布bool RXTruetable[100]={0};//CAD后能接收正确的分布uint8_t CadDetectedTime=0;//检测到的cad的次数uint8_t RxCorrectTime=0;//RX 接收正确次数uint8_t TxTime=0;		//TX 次数//连续发送的时候用uint8_t ModulationParam[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };uint8_t PacketParam[9] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };/* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* Configure the system clock */SystemClock_Config();/* Initialize all configured peripherals */MX_GPIO_Init();MX_SPI1_Init();MX_USART1_UART_Init();MX_USART2_UART_Init();MX_USART3_UART_Init();wifi_protocol_init();   //wifi协议初始化TIM3_Init(20-1,8000-1); //定时器3初始化,定时2msfor(i=0;i<1;i++){HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);HAL_Delay(1000);HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);HAL_Delay(1000);}SX126xReset();i=SX126xReadRegister(REG_LR_CRCSEEDBASEADDR);if(i==0x1D){   printf("SPI SUCCESS!\n\r");}else{printf("SPI Fail! REG_LR_CRCSEEDBASEADDR=%x\n\r",i);}RadioInit();SX126xWriteRegister(0x889, SX126xReadRegister(0x889) & 0xfB);//SdCfg0 (0x889) sd_res (bit 2) = 0 printf("RadioInit Done!\n\r");#if (TEST_MODE==0)   //infinite preamble TX mode//连续发送SX126xSetStandby( STDBY_RC );SX126xSetPacketType(PACKET_TYPE_LORA);//todo: 增加发射FSK模式下的改指令printf("set lora params\n");ModulationParam[0]=LORA_SPREADING_FACTOR;ModulationParam[1]=Bandwidths_copy[LORA_BANDWIDTH];ModulationParam[2]=LORA_CODINGRATE;ModulationParam[3]=0;//1:SF11 and SF12 0:其他 低速率优化  SX126xWriteCommand( RADIO_SET_MODULATIONPARAMS, ModulationParam, 4 );//lora发射参数配置//设置lora包参数PacketParam[0]=(LORA_PREAMBLE_LENGTH>>8)& 0xFF;PacketParam[1]=LORA_PREAMBLE_LENGTH;PacketParam[2]=LORA_FIX_LENGTH_PAYLOAD_ON;//head typePacketParam[3]=0xFF;//0Xff is MaxPayloadLengthPacketParam[4]=true;//CRC onPacketParam[5]=LORA_IQ_INVERSION_ON;SX126xWriteCommand( RADIO_SET_PACKETPARAMS, PacketParam, 6 );//SX126xWriteBuffer( 0x00, SendData, 10 );//连续发送loraSX126xSetRfFrequency( RF_FREQUENCY );SX126xSetRfTxPower( TX_OUTPUT_POWER );SX126xSetTxInfinitePreamble();printf("TxContinuousWave Now--infinite preamble!\n\r");while(1);
#elif (TEST_MODE==1) //TX CWRadioSetTxContinuousWave( RF_FREQUENCY, TX_OUTPUT_POWER, TX_TIMEOUT );printf("TxContinuousWave Now---CW!\n\r");while(1);#endif#if (FSK_MODE==1)SX126xSetRfFrequency(RF_FREQUENCY);RadioSetTxConfig( MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, FSK_BANDWIDTH,FSK_DATARATE, 0,FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON,true, 0, 0, 0, 3000 );RadioSetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE,0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH,0, FSK_FIX_LENGTH_PAYLOAD_ON, FSK_FIX_LENGTH_PAYLOAD, FSK_CRC,0, 0,false, RX_CONTINOUS );printf("FSK:%d,Fdev=%ld,BitRate=%ld,BW=%ld,PWR=%d,PreLen=%d,PYLOAD=%d\n\r",RF_FREQUENCY,FSK_FDEV,FSK_DATARATE,FSK_BANDWIDTH,TX_OUTPUT_POWER,FSK_PREAMBLE_LENGTH,BUFFER_SIZE);printf("configure FSK parameters done\n!");#elif (LORA_MODE==1)SX126xSetRfFrequency(RF_FREQUENCY);RadioSetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,LORA_SPREADING_FACTOR, LORA_CODINGRATE,LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,true, 0, 0, LORA_IQ_INVERSION_ON, 3000 );RadioSetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,0, true, 0, 0, LORA_IQ_INVERSION_ON, RX_CONTINOUS );//最后一个参数设置是否是连续接收printf("LORA:%d,SF=%d,codeRate=%d,BW=%d,PWR=%d,PreLen=%d,PYLOAD=%d\n\r",RF_FREQUENCY,LORA_SPREADING_FACTOR,LORA_CODINGRATE,LORA_BANDWIDTH,TX_OUTPUT_POWER,LORA_PREAMBLE_LENGTH,BUFFER_SIZE);if (RadioPublicNetwork.Previous==true && RadioPublicNetwork.Current==false)printf("public\n\r");else if (RadioPublicNetwork.Previous==false && RadioPublicNetwork.Current==false)printf("private\n\r");printf("configure LORA parameters done\n!");#endifwhile (1){#if (TRANSMITTER==1)while(1){Buffer[0] = TxTime++;Buffer[1] = 1;Buffer[2] = 2;Buffer[3] = 3;Buffer[4] = 0;Buffer[5] = 0;RadioSend(Buffer,20);while(TXDone==false && TimeOutFlag==false);//一直等待tx doneTXDone=false;TimeOutFlag=false;printf("TxTime=%d\n",TxTime);HAL_Delay(500); ///1s//读取状态RadioStatus=SX126xGetStatus();printf("RadioStatus is(after TX_DONE) %d\n",(((RadioStatus.Value)>>4)&0x07));}
#elif (RECEIVER==1) 
while(1){	
#if (RX_CONTINOUS==1)//开始接收	RadioRx(0xFFFFFF);//50MS(0XC80)超时  0-单次接收 无超时printf("continous RX...\n");while(1);//连续接收
#endifRadioRx(2000);//50MS(0XC80)超时  0-单次接收 无超时while(RXDoneFlag==false && TimeOutFlag==false && CRCFail==false);if(RXDoneFlag==true || TimeOutFlag==true || CRCFail==true){if(CRCFail==false)	//CRC无错误{if(RXDoneFlag==true){printf("\n%d:RxCorrect-PING\n",RxCorrectTime);RxCorrectTime++;}}CRCFail=false;RXDoneFlag=false;TimeOutFlag=false;}}
#endif		  
}
}

本demo接收部分完整工程:[点此下载](Tuya-Community/tuya-iotos-embeded-mcu-demo-wifi-ble-STM32_LORA_LCD_RECEIVE (github.com))

五、小结

​ 至此智能农业场景搭建就完成了,它可以APP远程控制、本地控制等。大家可以在此基础上实现尽可能多的功能。同时您可以基于涂鸦IoT平台丰富它的功能,也可以更加方便的搭建更多智能产品原型,加速智能产品的开发流程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/66787.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

win10将硬盘作为存储池删除读不到盘符_一篇文章让你理解Ceph的三种存储接口(块设备、文件系统、对象存储)...

“Ceph是一个开源的、统一的、分布式的存储系统”&#xff0c;这是我们宣传Ceph时常说的一句话&#xff0c;其中“统一”是说Ceph可以一套存储系统同时提供块设备存储、文件系统存储和对象存储三种存储功能。一听这句话&#xff0c;具有一定存储基础的用户应该已经大致了解了Ce…

谷款量子计算机用了多少光子,中国光量子计算机诞生 脑容量小的别看

原标题&#xff1a;中国光量子计算机诞生 脑容量小的别看 “去和古代一个使用算盘的账房先生解释&#xff0c;我们给你制造出一种可以算得飞快的全新工具(计算机)&#xff0c;于是账房先生开始想&#xff0c;这到底是一种什么样的新算盘&#xff1f;是玻璃珠子&#xff1f;还是…

html5文字开始空两格,一段文字的开头为什么要空两格

有一个简书作者&#xff0c;名叫上官皖又名官皖儿&#xff0c;是中国著名新闻人(总编辑)&#xff0c;他刚才点赞我文&#xff0c;我打开他的主页阅读他的文章&#xff0c;其中有一篇讲到&#xff0c;学生试卷分数下边两条杠究竟是怎么来的。 图片发自简书App 这是生活里一个简单…

一百个你不应该继续用Dev C++的理由

这篇文章来源于一家台湾网站&#xff0c;看完之后觉得很有感想&#xff0c;就分享给大家了。现在NOIP复赛使用的DevC4.9.9.2都是10年前的老东西了&#xff0c;还有无数的大学教授甚至要求使用Win8的学生安装DevC&#xff0c;也不管装上之后能不能用。感觉新一届码农被这个坑爹的…

一个人做饭有哪些推荐?

Chen Sam &#xff0c;一个空号。 355 人赞同 -- 2015.12.28. 一个圣诞节长周末多了100个赞..Whats going on here..感恩。 有同学私信说需要详细步骤的做饭教程&#xff0c;但是这里篇幅太局限了..如果开一个微信公众号什么的有人会想看吗&#xff1f; 第一次认认真真地在知乎…

中国最美的一千个汉字 : 千字文2

中国最美的一千个汉字 : 千字文2 容止若思&#xff0c;言辞安定。 仪容举止要沉静安详&#xff0c;言语措辞要稳重&#xff0c;显得从容沉静。 image image image image image image image image 笃初诚美&#xff0c;慎终宜令。 无论修身、求学、重视开头固然不错&#xff0c;…

“码农”一词是怎么来的?为什么中国程序员会被码农?程序员和农民有什么关联?

原创: 思齐大神 来源:蚁开源社区 很多同学会问,IT行业在中国并不是特别差的行业,而程序员的工资也并不低,但为什么中国的程序员总被称作码农或者说是苦逼的程序员?中国的程序员生活和欧美的有什么不一样? ​ 先说两个小段子 街边,一对情侣在吵架。女孩对男孩说,“我…

中国最美的一千个汉字 : 千字文

千字文 【作者】周兴嗣 【朝代】南北朝 天地玄黄&#xff0c;宇宙洪荒。 天是青黑色的&#xff0c;地是黄色的&#xff0c;宇宙形成于混沌蒙昧的状态中。 天 地 地 玄 黄 宇 宙 洪 荒 日月盈昃&#xff0c;辰宿列张。 太阳正了又斜&#xff0c;月亮圆了又缺&#xff0c;星辰布满…

哪个期货公司手续费低高交返?

只要选择的期货公司&#xff1a;手续费1分、高额比例交返、保证金0&#xff0c;经纪人专业可靠&#xff0c;综合势力完善&#xff0c;开户可以通过开户云办理&#xff0c;那你选择的公司就是好期货公司&#xff0c;其它一切都是浮云&#xff0c;预祝大家投资顺利&#xff0c;能…

哪种手续费的期货公司比较好?

哪种手续费的期货公司比较好&#xff1f; 建议超过0.5倍手续费的公司就可以不用考虑了&#xff0c;最好也别找加倍数的&#xff0c;比如0.1倍、0.2倍这种&#xff0c;因为如果交易所上调手续费时&#xff0c;加倍数的也会跟着上涨&#xff0c;不划算&#xff0c;就找加一分这种…

券商投行如何打搭建工作底稿系统?

2008年&#xff0c;中国证监会下发《关于建立上市公司重大资产重组独立财务顾问工作底稿科技管理系统的通知》&#xff0c;这是首次以成文的形式要求工作底稿接受电子化管控。2020年2月28日&#xff0c;中国证券业协会发布《证券公司投资银行类业务工作底稿电子化管理系统建设指…

投行女自述:我的投行生涯

<span class"img1"> <a href"http://news.sina.com.cn/437/2008/0703/24.html" target"_blank"><img width"16" height"18" align"absmiddle" title"此博文通过手机撰写(手机访问sina.cn)&qu…

文章刚刚开源就被培训机构“BP”了,过于不要脸

大家好&#xff0c;我是冰河~~ 事情是这样的&#xff0c;上周我把一些文章开源了&#xff0c;没想到才开源几天&#xff0c;就被一个不要脸的培训机构直接拿去当课件了&#xff0c;这个事情开始我也不知道&#xff0c;还是一名读者告诉我的。 本来开源这些文章&#xff0c;想的…

能否做好PB业务,可能正成为拉开券商差距的分水岭

转自&#xff1a;https://xueqiu.com/9177020418/89211078 读后总结&#xff1a; PB业务是指证券公司向专业机构投资者和高净值客户等提供集中托管清算、后台运营、研究支持、杠杆融资、证券拆借、资金募集等一站式综合金融服务 PB业务有望成为券商新的增长点&#xff0c;因为…

在中国,咨询公司为啥不值钱?

&#xff08;1&#xff09;知识与经验 一、知识&#xff1a;体系性的方法论工具 中国MBA教育虽然经常目的被扭曲为人脉结识好做买卖&#xff0c;但MBA的课程确实是教人们体系性的方法论工具。越来越多的管理者也都接受过了MBA知识普及。 二、经验 把A企业的经验卖到B企业。这其…

曾经辉煌的投行自营团队,现今何处?

量化投资与机器学习微信公众号&#xff0c;是业内垂直于量化投资、对冲基金、Fintech、人工智能、大数据等领域的主流自媒体。公众号拥有来自公募、私募、券商、期货、银行、保险、高校等行业30W关注者&#xff0c;荣获2021年度AMMA优秀品牌力、优秀洞察力大奖&#xff0c;连续…

人在新加坡,刚下飞机,原地失业!上交大佬刚到新加坡,就被虾皮取消了offer,作者发声了......

上一篇&#xff1a;想要我加班&#xff1f;门都没有。怼的太爽了吧 编辑&#xff1a;Aeneas 好困&#xff0c;转载自新智元 近日&#xff0c;接到虾皮offer的一位网友&#xff0c;携家带口飞到了新加坡&#xff0c;结果一下飞机就发现自己失业了。虾皮这波大规模毁offer操作&am…

公务员考试催生一家上市公司,公务员真的是一条好的出路吗

公务员考试能催生一家公司吗&#xff1f;还真的可以&#xff0c;而且在2023.01.09日也就是今天上市。公务员真的是一条好的出路吗&#xff0c;现在考公务员还行不行&#xff1f;这需要结合我们当下的环境来综合分析。我们都经历了疫情&#xff0c;期间各个大厂频频将裁员大棒挥…

用计算机弹琴琴谱,在电脑上弹钢琴的软件

真钢琴很贵&#xff0c;大多数人家都没有钢琴&#xff0c;您是否想在电脑上弹钢琴呢?特此本站发布一款非常好用的在电脑上弹钢琴的软件&#xff0c;希望大家喜欢。使用该电脑弹钢琴软件您可以使用普通的电脑键盘演奏出美妙的钢琴曲并且自带音色库。 界面预览图&#xff1a; 钢…

用Python演奏《国际歌》

文章目录 一、背景与需求二、必备知识2.1 Python生成音乐的原理2.2 十二平均律2.3 简单乐理知识 三、实现3.1 对琴谱进行编码3.2 Music类3.3 Staff类3.4 Converter类 四、项目代码五、不足与展望 一、背景与需求 前一段时间在B站看到一个视频&#xff0c;up主用matlab演奏出了…