题目
蓝桥杯大赛历届真题 - 物联网设计与开发科目模拟试题 - 蓝桥云课 (lanqiao.cn)
看题目,
A板涉及继电器K1,K2,按键USER,通信LoRa,显示OLED。
B板涉及ADC,LoRa,OLED。
题目分析
A板
分析题目,A板没有插扩展板,只需要写oled显示,user按键,Lora信息传输三个功能函数
OLED:显示K1-LED,K2-LED的亮灭状态
USER:每次按下通过lora传输数据
LoRa:传输数据,注意地址配置。
B板
分析题目,B板扩展了模拟输出&指示灯模块,需要写adc采集数据,oled显示,Lora信息传输三个功能函数
ADC:采集电压值
OLED:根据a板发送的信息,更新显示REC,ADC的数值
LoRa:传输数据
题目解答
A板CubeMax配置
这里注意几个点:
1.配置PC15的LED用于显示lora传输状态,高电平熄灭,低电平点亮
2.PC14的USER按键配置成外部中断模式,下降沿触发,这样可以及时响应
3.I2C3的oled要配置PB5引脚,这是oled的供电引脚
4.LoRa要配置PA4,PA10,PA9这三个脚,是LORA的片选,中断,和复位
使能时钟32MHz,就可以输出代码了。
添加OLED.c OLED.h LoRa.C LoRa.h的底层驱动文件到Inc,Src文件夹内,编译
A板功能代码编写
在i2c.c的初始化函数void MX_I2C3_Init(void)用户沙箱内添加100ms延时函数,用于OLED的充电等待
i2c.c中的函数用户沙箱内添加接口函数
/**
* @brief OLED写入函数
* @param Type,Data
* @retval 无
*/
void OLED_Write(uint8_t Type,uint8_t Data)
{
uint8_t pData[2];
pData[0] = Type;
pData[1] = Data;
HAL_I2C_Master_Transmit(&hi2c3,0x78,pData,2,10);
}
在spi.c的初始化函数void MX_SPI1_Init(void)的用户沙箱内拉高PA4,PA9。这是lora的片选和复位引脚,初始使能两个引脚。
spi.c中的函数用户沙箱内添加接口函数
/**
* @brief spi命令写入/读取
* @param ucAddr Data
* @retval pRxData[1]
*/
uint8_t SPI_WriteRead(uint8_t ucAddr,uint8_t Data)
{
uint8_t pTxData[2],pRxData[2];
pTxData[0] = ucAddr;
pTxData[1] = Data;
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];
}
在main.c中的函数用户沙箱内添加功能函数
定义变量
uint8_t A_Addr[7]={0x14,0x02,0x35,0x69,0x41,0x0A,0x01};
uint8_t B_Addr[7]={0x14,0x02,0x35,0x69,0x42,0x0B,0x11};
uint8_t ucStata;
uint8_t *ubuff;
数据传输和显示
void OLED_Proc(uint8_t ucStata)
{
uint8_t *buff;
switch(ucStata)
{
case 0x11:
HAL_GPIO_WritePin(K1_GPIO_Port,K1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(K2_GPIO_Port,K2_Pin,GPIO_PIN_RESET);
sprintf((char *)buff,"K1-LED: ON");
OLED_ShowString(0,0,buff,16);
sprintf((char *)buff,"K2-LED:OFF");
OLED_ShowString(0,2,buff,16);break;
case 0x12:
HAL_GPIO_WritePin(K1_GPIO_Port,K1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(K2_GPIO_Port,K2_Pin,GPIO_PIN_SET);
sprintf((char *)buff,"K1-LED:OFF");
OLED_ShowString(0,0,buff,16);
sprintf((char *)buff,"K2-LED: ON");
OLED_ShowString(0,2,buff,16);break;
case 0x13:
HAL_GPIO_WritePin(K1_GPIO_Port,K1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(K2_GPIO_Port,K2_Pin,GPIO_PIN_RESET);
sprintf((char *)buff,"K1-LED:OFF");
OLED_ShowString(0,0,buff,16);
sprintf((char *)buff,"K2-LED:OFF");
OLED_ShowString(0,2,buff,16);break;
}
}
void Lora_Porc(uint8_t Addr[])
{
uint8_t buff[7],count=0;
LORA_Tx(Addr,7);
if(LORA_Rx(buff) == 7)
{
for(int i=0;i<5;i++)
if(buff[i]==B_Addr[i])
count++;
}
if(count == 5)
ucStata = buff[6];
}
在中断回调函数中调用两个中断函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
while(HAL_GPIO_ReadPin(USER_GPIO_Port,USER_Pin) == 0);//检测松手
Lora_Porc(A_Addr);
OLED_Proc(ucStata);
HAL_GPIO_TogglePin(LD5_GPIO_Port,LD5_Pin);//测试代码
}
这样A板就写好了
B板CubeMax配置
和A板的配置相似,增加了ADC采集,使能IN8,注意使能低功率等待
B板功能代码编写
oled和lora的底层代码与A板一致,在adc的void MX_ADC_Init(void)初始化函数中添加自动转换函数
HAL_ADCEx_Calibration_Start(&hadc,ADC_SINGLE_ENDED);
添加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);
HAL_GPIO_TogglePin(LD1_GPIO_Port,LD1_Pin);
}
if(HAL_ADC_PollForConversion(&hadc,10) == HAL_OK)
{
usData[1] = HAL_ADC_GetValue(&hadc);
//HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);
}
}
在main.c中添加功能代码
定义变量
uint8_t A_Addr[7]={0x14,0x02,0x35,0x69,0x41,0x0A,0x01};
uint8_t B_Addr[7]={0x14,0x02,0x35,0x69,0x42,0x0B,0x11};
uint16_t ucADC[2];
uint8_t stata;
OLED,LORA功能函数
void LORA_Proc(void)
{
uint8_t buff[7],count=0,command;
if(LORA_Rx(buff) == 7) //地址判断
for(int i = 0;i < 5;i ++)
{
if(A_Addr[i] == buff[i])
count++;
}
if(count == 5 && buff[6] == 0x01) //地址码正确,命令码正确
{
stata = 1; //改变OLED显示状态
ADC_Read(ucADC); //读取ADC
if(ucADC[0]*3.3/4095 < 1.5) //判断ADC的电压区间
command = 0x11;
else if(ucADC[0]*3.3/4095 >= 1.5 && ucADC[0]*3.3/4095 < 2.5)
command = 0x12;
else if(ucADC[0]*3.3/4095 >= 2.5)
command = 0x13;
B_Addr[6] = command;//改变B的命令码
LORA_Tx(B_Addr,7);//发送B的地址码,命令码
}
}
void OLED_Proc(uint8_t stata)
{
uint8_t* buff;
if(stata==1) //切换显示状态,保持两秒
{
stata=0;
sprintf((char*)buff,"REC:OK ");
OLED_ShowString(0,0,buff,16);
sprintf((char*)buff,"ADC:%.2fV",ucADC[1]*3.3/4095);
OLED_ShowString(0,2,buff,16);
delay_ms(2000);
}
else
{
sprintf((char*)buff,"REC:None");
OLED_ShowString(0,0,buff,16);
sprintf((char*)buff,"ADC:None");
OLED_ShowString(0,2,buff,16);
}
}
void delay_ms(uint16_t ms) //自定义毫秒级延时函数
{
uint16_t i = 0;
while(ms--){
i=12000;
while(i--);
}
}
在主循环中调用这两个功能代码即可
这样B板的程序也写好了,编译下载,观察现象