第十三届省赛蓝桥杯物联网程序设计试题
一、真题部分
二、LoRa_A
1、配置根据试题的要求配置STM32CubeMX
(1)引脚配置
将PC14引脚配置为输入模式
PC14 用户按键引脚
将PA10引脚配置为中断模式
PA10 LoRa模块DIO0引脚
将以下引脚配置为输出模式
PC15 用户LED引脚
PB5 OLED电源控制引脚
PA11和PA12 继电器控制引脚
PA4和PA9 LoRa模块片选和复位引脚,初始为高电平
GPIO引脚初始化
使能EXTI4_15中断
(2)配置I2C模块,因为新版数据资源包需要自己创建I2C模块的程序,所以利用STM32CubeMX配置硬件I2C模块
(3)配置串口模块,波特率为9600Baud,允许串口全局中断
(4)配置LoRa通信所需的SPI串行设备接口(全双工、高速、同步通信总线)
MOSI:主设备输出/从设备输入引脚,该引脚在主模式下发送数据,从模式下接受数据,对应PA7引脚
MISO:主设备输入/从设备输出引脚,该引脚在从模式下发送数据,主模式下接受数据,对应PA6引脚
SCLK:串行时钟信号,由主设备产生,对应PA5引脚
(5)配置系统时钟,采用32MHz时钟
2、程序设计
(1)导入数据资源包中提供的代码
(2)由于利用STM32创建I2C和SPI模块缺少对应的函数,所以需要添加一部分代码,通过运行程序可以发现OLED_Write函数和SPI_WriteRead函数缺少相关的定义
在i2c.c函数中定义OLED_Write函数,同时在i2c.h中声明OLED_Write函数
void OLED_Write(uint8_t ucType,uint8_t ucData)
{
uint8_t pData[2];
pData[0]=ucType;
pData[1]=ucData;
HAL_I2C_Master_Transmit(&hi2c3, 0x78, pData, 2, 10);
}
在spi.c中定义SPI_WriteRead函数,同时在spi.h中声明SPI_WriteRead函数
uint8_t SPI_WriteRead(uint8_t ucAddr, uint8_t ucData)
{
uint8_t pTxData[2], pRxData[2];
pTxData[0] = ucAddr;
pTxData[1] = ucData;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1, pTxData, pRxData, 2, 10);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
return pRxData[1];
}
(3)在main.c定义任务初始化函数
void Task_Main()
{
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET);//OLED屏幕上电
HAL_Delay(200);//延时200ms十分重要,否则OLED可能无法显示
OLED_Init();
OLED_Clear();
LORA_Init();
OLED_ShowString(0,0,(uint8_t *)" ",16);
OLED_ShowString(0,2,(uint8_t *)" ",16);
OLED_ShowString(0,0,(uint8_t *)" RX: ",16);
OLED_ShowString(0,2,(uint8_t *)" NUM:0 ",16);
}
(4)在main.c中分别定义各个模块的函数
uint8_t RxData[16];
uint8_t TxData[5]="error";
char LCD_Line1st[16];
char LCD_Line2st[16];
uint8_t count=0;
uint8_t UART_Proc()
{
uint8_t ucValue=0;
HAL_UART_Receive(&huart2,RxData,1,500);
if(RxData[0]!=0)
{
if(RxData[0]=='@'||RxData[0]=='#'||RxData[0]=='$')
{
if(RxData[0]=='@'){
ucValue=1;
}
if(RxData[0]=='#'){
ucValue=2;
}
if(RxData[0]=='$'){
ucValue=3;
}
}
else
{
HAL_UART_Transmit(&huart2,TxData,sizeof(TxData),500);
ucValue=4;
}
return ucValue;
}
return 0;
}
void LED_Proc()
{
uint8_t ucValue=UART_Proc();
if(ucValue==1)
HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_15);
if(ucValue==2)
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_11);
if(ucValue==3)
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_12);
}
void OLED_Proc()
{
uint8_t ucValue=UART_Proc();
if(ucValue==1){
count=count+1;
sprintf(LCD_Line2st," RX:@");
OLED_ShowString(0,0,(uint8_t *)LCD_Line1st,16);
sprintf(LCD_Line2st," NUM:%d",count);
OLED_ShowString(0,2,(uint8_t *)LCD_Line2st,16);
}
if(ucValue==2){
count=count+1;
sprintf(LCD_Line2st," RX:#");
OLED_ShowString(0,0,(uint8_t *)LCD_Line1st,16);
sprintf(LCD_Line2st," NUM:%d",count);
OLED_ShowString(0,2,(uint8_t *)LCD_Line2st,16);
}
if(ucValue==3){
count=count+1;
sprintf(LCD_Line2st," RX:$");
OLED_ShowString(0,0,(uint8_t *)LCD_Line1st,16);
sprintf(LCD_Line2st," NUM:%d",count);
OLED_ShowString(0,2,(uint8_t *)LCD_Line2st,16);
}
if(ucValue==4){
if(count==0)
count=0;
else
count--;
sprintf(LCD_Line1st," RX:error");
OLED_ShowString(0,0,(uint8_t *)LCD_Line1st,16);
sprintf(LCD_Line2st," NUM:%d",count);
OLED_ShowString(0,2,(uint8_t *)LCD_Line2st,16);
}
}
void LORA_Proc()
{
uint8_t LD5=HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_15);
uint8_t K1=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11);
uint8_t K2=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12);
uint8_t pcBuf[3]={LD5,K1,K2};
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14)==GPIO_PIN_RESET)
LORA_Tx(pcBuf,3);
}
}
三、LoRa_B
1、配置根据试题要求配置STM32CubeMX
(1)引脚配置
将PC14引脚配置为输入模式
PC14 用户按键引脚
将PA10引脚配置为中断模式
PA10 LoRa模块DIO0引脚
将以下引脚配置为输出模式
PC15 用户LED引脚
PB5 OLED电源控制引脚
PA11和PA12 继电器控制引脚
PA4和PA9 LoRa模块片选和复位引脚,初始为高电平
使能EXTI4_15中断
(2)配置I2C模块,因为新版数据资源包需要自己创建I2C模块的程序,所以利用STM32CubeMX配置硬件I2C模块
(2)配置ADC模块,由原理图可以看出RP1对应引脚为PB1,RP2对应引脚为PB0,故使用ADC模块的8通道和9通道,同时需要DMA传输,将外设模块中的电压值传输到内存中
扫描模式是默认开启的,同时必须开启连续模式,否则采集一轮结束后不会继续采集,这样就不会触发DMA中断进入回调函数了。连续扫描模式下,多通道会根据length数量循环采集各通道,如ch8和ch9两通道,length为10的话,则adc_value[0][2][4][6][8]存放的就是ch8通道的采样值,adc_value[1][3][5][7][9]数组位置存放的是ch9的值:
(3)配置串口模块,通讯波特率为9600Baud,同时开启接受引脚的DMA传输
(4)配置LoRa通信所需的SPI串行设备接口(全双工、高速、同步通信总线)
MOSI:主设备输出/从设备输入引脚,该引脚在主模式下发送数据,从模式下接受数据,对应PA7引脚
MISO:主设备输入/从设备输出引脚,该引脚在从模式下发送数据,主模式下接受数据,对应PA6引脚
SCLK:串行时钟信号,由主设备产生,对应PA5引脚
(5)配置系统时钟,采用32MHz的时钟
2、程序设计
(1)导入数据资源包中的代码,配置底层接口,由于和LoRa_A部分方法一样,此处不再赘述,在spi.c和i2c.c中分别定义以下代码,但不要忘了在头文件中声明
void OLED_Write(uint8_t ucType,uint8_t ucData)
{
uint8_t pData[2];
pData[0]=ucType;
pData[1]=ucData;
HAL_I2C_Master_Transmit(&hi2c3,0x78,pData,2,10);
}
uint8_t SPI_WriteRead(uint8_t ucAddr,uint8_t ucData)
{
uint8_t pTxData[2],pRxData[2];
pTxData[0]=ucAddr;
pRxData[1]=ucData;
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(&hspi1,pTxData,pRxData,2,10);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
return pRxData[1];
}
(2)主体函数设计
char ucBuf[16]; //OLED转换值
uint8_t usADC[2];//ADC转换值
uint8_t count=0;//存储同步次数
uint8_t RxData[3];//存储LORA接受值
/*PA10中断函数,用于接受LROA发送过来的数据*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == GPIO_PIN_10)
{
count++;
LORA_Rx(RxData);
}
}
/*ADC读取函数*/
void ADC_Read(uint16_t *usData)
{
HAL_ADC_Start(&hadc);
if(HAL_ADC_PollForConversion(&hadc, 10) == HAL_OK)
usData[0] = HAL_ADC_GetValue(&hadc);//RP2
if(HAL_ADC_PollForConversion(&hadc, 10) == HAL_OK)
usData[1] = HAL_ADC_GetValue(&hadc);//RP1
}
/*ADC转换函数,将转换后的值显示在OLED对应的位置上*/
void ADC_Proc()
{
ADC_Read(usADC);
sprintf(ucBuf, " RP2:%3.1fV", usADC[0]*3.3/4095);
OLED_ShowString(0, 0, (uint8_t *)ucBuf, 16);
sprintf(ucBuf, " RP1:%3.1fV", usADC[1]*3.3/4095);
OLED_ShowString(0, 2, (uint8_t *)ucBuf, 16);
}
/*状态显示函数*/
void State_Proc()
{
sprintf(ucBuf," NUM:%d ",count);
OLED_ShowString(0,0,(uint8_t *)ucBuf,16);
if(RxData[1]==GPIO_PIN_SET&&RxData[2]==GPIO_PIN_SET)
{
sprintf(ucBuf," STA:ON ");
OLED_ShowString(0,2,(uint8_t *)ucBuf,16);
}
else
{
sprintf(ucBuf," STA:OFF ");
OLED_ShowString(0,2,(uint8_t *)ucBuf,16);
}
}
/*OLED屏幕界面切换函数*/
void OLED_Proc()
{
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14)==GPIO_PIN_RESET)
ucState^=1;
}
if(ucState==0)
ADC_Proc();
else
State_Proc();
}
/*将A板对应的LED灯状态同步到B板*/
void LED_Proc()
{
if(RxData[0]==GPIO_PIN_RESET)
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_RESET);
else
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_SET);
if(RxData[1]==GPIO_PIN_RESET)
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_RESET);
else
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_SET);
if(RxData[2]==GPIO_PIN_RESET)
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_RESET);
else
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_SET);
}
(3)在主函数中调用OLED_Proc()函数和LED_Proc()函数即可