蓝桥杯物联网——模块熟知
1.LED
贴片: LED5 →PC15控制,低电平亮
继电器控制: K1-LED→PA0控制,高电平亮
继电器控制: K2-LED→PA1控制,高电平亮
2.USER摁键
由PC14控制,摁下为0,平时为1(应配为上拉)
长摁与短摁的实现:
unsigned int KEY_flag=0;
uint16_t count=0;
void Key_scan() //直接将扫描函数丢到定时器里
{
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14)==0) //摁键摁下
{
count++;
}
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_14)==1) //摁键松开
{
if(count>1&&count<100) //利用定时器判断摁下时间
{
KEY_flag=1;
}
if(count>=100) //按下经过1s 10*100ms=1s
{
KEY_flag=2;
}
count=0;
}
}
void Led_scan()
{
if(KEY_flag==1)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_RESET);
}
if(KEY_flag==2)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_SET);
}
}
3.显示屏OLED
打开参考文件已有初始化函数 void Task_BrdInit(void);将其放在BEGIN与END之间,再配置CubeMX,就不会因为重新生成工程而不见了。
用到最多的无非两个函数sprintf()、OLED_ShowString();啥都ok
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O4GGVyO5-1650242988004)(4.%E8%93%9D%E6%A1%A5%E6%9D%AF%E7%89%A9%E8%81%94%E7%BD%91%E2%80%94%E2%80%94%E6%A8%A1%E5%9D%97.assets/image-20220214175232026.png)]
①解决显示屏不清位问题(7位变5位多两位不清除)
void OLED_ShowString(uint8_t x, uint8_t y, uint8_t *chr, uint8_t Char_Size)
{
//由函数初始值可知,字符串第一位显示的位置x,也可计算出字符串的长度
unsigned char j = 0,x1;
x1=x; //保存字符串第一位显示的位置x
while (chr[j] != '\0')
{
OLED_ShowChar(x, y, chr[j], Char_Size);
x += 8;
if(x > 120)
{
x = 0;
y += 2;
}
j++;
}
for(j=0;j<x1;j=j+8) //从第0位到第一位显示的位置x,都用空格显示
{
//细节:每8位为一个字节的宽度
OLED_ShowChar(j, y, ' ', Char_Size);
}
for(j=x;j<128;j=j+8) //从字符串最后一位的位置到显示屏能显示的最长位置128,都用空格显示
{
OLED_ShowChar(j, y, ' ', Char_Size);
}
}
②OLED屏显示占用系统教程,影响其他模块灵敏度(比如摁键不灵敏)
if(time_100ms==1) //使用定时器产生100ms,每隔100ms启动一次显示屏,对其他程序就不会造成影响
{
OLED_ShowString(0, 0, (unsigned char *)lcdLine_1st_line, 16);
OLED_ShowString(0, 2, (unsigned char *)lcdLine_2st_line, 16);
time_100ms=0; //执行一次之后令定时器重新计时
}
4.矩阵摁键
行:PB6(上)、PB7(下)——这两引脚用来输入
列:PB1(左)、PB0(中)、PA8(右)
其中PA8引脚与显示屏的时钟scl引脚撞了
注意的点:
①GPIO的引脚配置:GPIO_InitStruct.Pull = GPIO_PULLDOWN;{GPIO_ULLUP(上拉)、GPIO_ULLDOWN(下拉)、GPIO_NOPULL(既不上拉也不下拉),这几个参数指的是引脚无操作时保持的状态,上拉高电平,下拉低电平。必须结合摁键扫描来配置}
②部分代码:三处小细节
unsigned int KEY_flag; //该函数为摁键标志位,须使用extern宏定义 void key_scan() //此函数利用定时器10ms消抖,不再使用额外消抖 { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6)) KEY_flag=11; if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7)) KEY_flag=21; HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6)) KEY_flag=12; if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7)) KEY_flag=22; HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6)) KEY_flag=13; if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7)) KEY_flag=23; } void Led_scan() //执行函数,什么摁键执行命令 { if(KEY_flag==11) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_SET); } if(KEY_flag==21) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_RESET); } } ---------------------------------------------------------------------------------------------------- main函数里的调用: if(time_10ms==1) //此处用定时器定时10ms key_scan(); Led_scan();
③如果没用到B3,B6键,就别开,会有延时影响。
5.ADC
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hvKawHz2-1650242988005)(4.%E8%93%9D%E6%A1%A5%E6%9D%AF%E7%89%A9%E8%81%94%E7%BD%91%E2%80%94%E2%80%94%E6%A8%A1%E5%9D%97.assets/image-20220214180429857.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M5yx2CdJ-1650242988005)(4.%E8%93%9D%E6%A1%A5%E6%9D%AF%E7%89%A9%E8%81%94%E7%BD%91%E2%80%94%E2%80%94%E6%A8%A1%E5%9D%97.assets/image-20220222182649799.png)]
注意:配置完初始状态,要将ADC中断打开(ADC也有中断!)
用到无非三个函数:
for(i=0;i<=1;i++) { HAL_ADC_Start(&hadc); //启动ADC if(HAL_ADC_PollForConversion(&hadc,100)==HAL_OK) //等待转换完成,延时时间100ms ad[i]=HAL_ADC_GetValue(&hadc)*(3.3/4095); //获取AD数值(0-4095),需要转为电压值。 } //获取一个通道AD值,再次循环可获得第二个通道
6.温度传感器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gi5mJ3nU-1650242988006)(4.%E8%93%9D%E6%A1%A5%E6%9D%AF%E7%89%A9%E8%81%94%E7%BD%91%E2%80%94%E2%80%94%E6%A8%A1%E5%9D%97.assets/image-20220214180540002.png)]
7.RTC时钟
在STM32CubeMX中找到RCT,
勾选两项:Activate Clock Source(激活时钟)、Activate Calendar(激活日历)
设置同步预分频——307
使用十进制
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EgYfK0vd-1650242988007)(4.%E8%93%9D%E6%A1%A5%E6%9D%AF%E7%89%A9%E8%81%94%E7%BD%91%E2%80%94%E2%80%94%E6%A8%A1%E5%9D%97.assets/image-20220222191155901.png)]
8.外部中断
只需在stm32l0xx_it.c文件中找到HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10)中断函数并进入其定义,即可找到回调函数HAL_GPIO_EXTI_Callback(GPIO_Pin)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) //中断回调函数
{
if(GPIO_Pin==GPIO_PIN_10) //判断中断是哪个引脚产生的,严谨性
{
;
}
}
9.定时器中断
1.普通定时器(TIM6,TIM7)
①配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lwoEHleo-1650242988008)(4.%E8%93%9D%E6%A1%A5%E6%9D%AF%E7%89%A9%E8%81%94%E7%BD%91%E2%80%94%E2%80%94%E6%A8%A1%E5%9D%97.assets/image-20220315222302950.png)]
定时器的计算公式:T=(arr+1)*(psc+1)/CLK。其中,CLK是MCU的时钟频率,arr和psc分别为自动重装载值和预分频系数。
比如定时1毫秒,假设时钟频率为32MHZ,只需要设定arr和psc分别为999和31就可以了。计算如下:1ms=(31+1)*(999+1)/32MHZ。值得注意的是,arr和psc分别为31和999也可以
②代码
只用到两个函数即可HAL_TIM_Base_Start_IT(&htim6) 与 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
HAL_TIM_Base_Start_IT(&htim6) 函数:放在while循环前即可使能定时器
→在stm32l0xx_hal_tim.c文件里,搜索start即可找到该函数
HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)函数:定时器回调函数,放在main函数外
→在stm32l0xx_hal_tim.c文件里,搜索==__weak==即可找到该函数(多找几下就有了)
2.通用定时器(TIM2,TIM3),一般只用来输出PWM
①配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TBJPCDfw-1650242988008)(4.%E8%93%9D%E6%A1%A5%E6%9D%AF%E7%89%A9%E8%81%94%E7%BD%91%E2%80%94%E2%80%94%E6%A8%A1%E5%9D%97.assets/QQ%E6%88%AA%E5%9B%BE20220329194902.png)]
②代码
只用到两个函数即可HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3) 与 __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,500);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3)函数:放在while函数之前即可使能PWM
→在stm32l0xx_hal_tim.c文件里,搜索PWM即可找到该函数
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_3,500)函数:用做比较PWM输出,其中500与重装载值999的比值,就是输出PWM的占空比
→在stm32l0xx_hal_tim.c文件里,搜索compare即可找到该函数
10.串口
①因为存在系统CPU占用过多,所以直接使用DMA传输(既可以省系统时间,也可以忽略数据量过大)
②一般使用空闲中断接收数据(既可以确定长度也可以不定长度的数据)
③DMA配置细节,一般只配置输入单片机(rx)的DMA,不配置输出(tx)。因为DMA不能同时双向传输,本身串口也不是全双工。
// main函数里的初始化
__HAL_UART_CLEAR_IDLEFLAG(&huart2);
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart2,reply,50);
void rx2(void) //需将rx2()放在void USART2_IRQHandler(void)串口中断函数里
{
if(RESET != __HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE)) //判断是否是空闲中断
{
__HAL_UART_CLEAR_IDLEFLAG(&huart2); //清除空闲中断标志(否则会一直不断进入中断)
HAL_UART_DMAStop(&huart2);
uart_flag=1; //设置串口已接收的标志位
HAL_UART_Receive_DMA(&huart2,reply,50); //重启开始DMA传输 每次255字节数据
}
}
11.CRC校验
找到CRC,勾选,keil里调用函数使用就行了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CFRXMy9u-1650242988009)(4.%E8%93%9D%E6%A1%A5%E6%9D%AF%E7%89%A9%E8%81%94%E7%BD%91%E2%80%94%E2%80%94%E6%A8%A1%E5%9D%97.assets/image-20220214174928266.png)]
常用函数
①对变量进行处理
sprintf()函数:数字变字符串
char lcdLine_1st_line[16];
sprintf(lcdLine_1st_line, “%f”,tem);
tem为数字,sprintf()的作用为把数字转为char类型的字符串
sscanf()函数:字符串变数字
① sscanf( (char *)rx,“%d-%d-%d”,&h,&m,&s); //将字符串转数字
② sscanf(“654321abcdedfABCDEF”, “%[1-9a-z]”, str); //取仅包含指定字符集的字符串
printf(“str=%s\n”, str); //str=654321abcded,只取数字和小写字符③ sscanf("zhoue3456 ", “%4s”, str); //取指定长度的字符串
printf(“str=%s\n”, str); //str=“zhou”;④ sscanf(“BCDEF123456abcdedf”, “%[ ^ a-z]”, str); //取到指定字符集为止的字符串
printf(“str=%s\n”, str); // str=BCDEF123456, 取遇到大写字母为止的字符串
strlen()函数:测量字符串实际长度(不包含‘\0’)
char b[]=“love”;
printf(“%ld\n”,strlen(b)); //结果为4
strcat()函数:字符串拼接
adc=strcat(lcdLine_1st_line," ");
adc=strcat(adc,lcdLine_2st_line);
也可自己写:
char a[100]="123",b[]="321",c; unsigned int i,i1,i2; i1=strlen(a); i2=strlen(b); for(i=0;i<=i2-1;i++) { a[i+i1]=b[i]; } printf("%s",a); //输出123321
sizeof()函数:测量字符串字节大小——所占内存(一般用不到)
unsigned int lon;
char lcdLine_1st_line[16];
lon=sizeof(lcdLine_1st_line);
sizeof()的作用是测量字符串包含的字符个数。
②位运算
a | b | a&b(且) | a|b(或) | a^b(异或) | ~a(位反) | !a(值反) |
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 1 | 0 |
0 | 1 | 0 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 | 0 | 0 |
1 | 1 | 1 | 1 | 0 | 0 | 0 |
文章评论