目录
一、adc
原理图引脚配置
Adc通道使能配置
Adc是将一个模拟的值Adc通道使能配置
转化为一个电压的值
ADC2通道使能及模式设置
之后点击生成即可
实例测试
效果显示
显示在第三行
案例程序
badc
/----------------------------badc.h---------------------------------------------/
cpp
#ifndef __BADC_H__
#define __BADC_H__
#include "main.h"
double getADC(ADC_HandleTypeDef *pin);
#endif
/-----------------------------badc.c---------------------------------------------/
cpp
#include "badc.h"
//读取adc值的函数
double getADC(ADC_HandleTypeDef *pin)
{
uint adc;//读出的原始值
HAL_ADC_Start(pin);//开启adc
adc = HAL_ADC_GetValue(pin);
return adc*3.3/4096;// 读取到的电压值,均分一个等分看在3.3所占的比例
}
/---------------------------------interrupt.h----------------------------------/
cpp
#ifndef __INTERRUPT_H__
#define __INTERRUPT_H__
#include "main.h"
#include "stdbool.h"
struct keys
{
uchar judge_sta;
bool key_sta;
bool single_flag;//确认被按下他为1
uint key_time; //判断按下的时间,时间比较长
uchar long_flag;
};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);
#endif
/---------------------------------interrupt.c----------------------------------/
按键相关函数
cpp
struct keys key[4] = {0,0,0};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM4)
{
key[0].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
key[1].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
key[2].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
key[3].key_sta = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
for(int i = 0;i<4;i++)
{
switch (key[i].judge_sta)
{
case 0:
{
if(key[i].key_sta == 0) //发现按键被按下
{
key[i].judge_sta=1;
key[i].key_time=0;//将时间清零
}
}
break;
case 1:
{
if(key[i].key_sta ==0)//消抖的过程里面就不能确定他短按键会与长按键冲突
{
key[i].judge_sta=2;
}
else key[i].judge_sta=0;
}
break;
case 2:
{
if(key[i].key_sta==1)//长按
{
key[i].judge_sta=0;
if(key[i].key_time<70)
{
key[i].single_flag = 1;
}
}
else
{
key[i].key_time++;//在他没有松开的打断时间内
if(key[i].key_time>70) key[i].long_flag=1;
}
}
break;
case 3:
{
}
break;
}
}
}
}
测量频率+占空比
cpp
double ccrl_val1a = 0,ccrl_val2a = 0;
uint ccr1_val1b=0,ccr1_val2b=0;
uint frq1=0,frq2=0; //频率
float duty1=0,duty2=0;//占空比
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM2)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)//中段消息来源 选择直接输入的通道
{
ccrl_val1a= HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1); //计时值hal库的计时函数 直接
ccr1_val1b= HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2); //计时值hal库的计时函数 间接
__HAL_TIM_SetCounter(htim,0);//计时值清零
frq1=(80000000/80)/ccrl_val1a;//计算频率
duty1=(ccr1_val1b/ccrl_val1a)*100;
HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);//从小打开定时器
HAL_TIM_IC_Start(htim,TIM_CHANNEL_2);//从小打开定时器
}
}
if(htim->Instance==TIM3)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)//中段消息来源 选择直接输入的通道
{
ccrl_val2a= HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1); //计时值hal库的计时函数 直接
ccr1_val2b= HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2); //计时值hal库的计时函数 间接
__HAL_TIM_SetCounter(htim,0);//计时值清零
frq2=(80000000/80)/ccrl_val2a;//计算频率
duty2=(ccr1_val2b/ccrl_val2a)*100;
HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);//从小打开定时器
HAL_TIM_IC_Start(htim,TIM_CHANNEL_2);//从小打开定时器
}
}
}
main.h
cpp
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "tim.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "led.h"
#include "lcd.h"
#include "stdio.h"
#include "interrupt.h"
#include "badc.h"
/* USER CODE END Includes */
/* USER CODE BEGIN PTD */
void key_proc(void);//按键的过程
void disp_proc(void);//显示界面的过程
extern struct keys key[];
extern uint frq1,frq2;//计算的到的回调值
extern float duty1,duty2;
uchar view=0;
uchar pa6_duty = 10;
uchar pa7_duty = 10;
/* USER CODE END PTD */
main
cpp
int main(void)
{
/* USER CODE BEGIN 2 */
LED_Disp(0x00);//LED初始化
LCD_Init();//LCD初始化
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
HAL_TIM_Base_Start_IT(&htim4); //定时器中断
HAL_TIM_PWM_Start(&htim16,TIM_CHANNEL_1);//打开pwm的输出通道
HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);//打开pwm的输通道
//打开定时器
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1); //定时器中断 频率测量捕获定时器开启
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1); //定时器中断
/* USER CODE END 2 */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
key_proc();
disp_proc();
// LED_Disp(0x02);
// HAL_Delay(500);
// LED_Disp(0x00);
// HAL_Delay(1000);
}
/* USER CODE END 3 */
}
按键的过程
cpp
/* USER CODE BEGIN 4 */
void key_proc(void)//按键的过程
{
if(key[0].single_flag ==1)
{
view=!view;
key[0].single_flag=0;
}
if(key[1].single_flag ==1)//按键2按下一次加10%
{
pa6_duty+=10;
if(pa6_duty>=100) pa6_duty=10;
__HAL_TIM_SetCompare(&htim16,TIM_CHANNEL_1,pa6_duty);//设置比较
key[1].single_flag=0;
}
if(key[2].single_flag ==1)//按键3 按下一次加10%
{
pa7_duty+=10;
if(pa7_duty>=100) pa7_duty=10;
__HAL_TIM_SetCompare(&htim17,TIM_CHANNEL_1,pa7_duty);//设置比较
key[2].single_flag=0;
}
}
显示界面的过程
cpp
void disp_proc(void)//显示界面的过程
{
if(view==0)
{
char text[30];
sprintf(text," Data ");
LCD_DisplayStringLine(Line1, (uint8_t *)text);
sprintf(text," FRQ1=%d ",frq1);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
sprintf(text," duty1=%.3f ",duty1);
LCD_DisplayStringLine(Line3, (uint8_t *)text);
sprintf(text," FRQ2=%d ",frq2);
LCD_DisplayStringLine(Line4, (uint8_t *)text);
sprintf(text," duty2=%.3f ",duty2);
LCD_DisplayStringLine(Line5, (uint8_t *)text);
//ADC显示 1 测量的是靠左的电位器
sprintf(text," V:=%.2f ",getADC(&hadc1));//在mx中配置了
LCD_DisplayStringLine(Line6, (uint8_t *)text);
//2
sprintf(text," V:=%.2f ",getADC(&hadc2));//在mx中配置了
LCD_DisplayStringLine(Line7, (uint8_t *)text);
}
if(view==1)//参数显示界面
{
char text[30];
sprintf(text," Para ");
LCD_DisplayStringLine(Line1, (uint8_t *)text);
sprintf(text," PA6:%d ",pa6_duty);
LCD_DisplayStringLine(Line3, (uint8_t *)text);
sprintf(text," PA7:%d ",pa7_duty);
LCD_DisplayStringLine(Line4, (uint8_t *)text);
//界面清理
sprintf(text," ");
LCD_DisplayStringLine(Line2, (uint8_t *)text);
sprintf(text," ");
LCD_DisplayStringLine(Line5, (uint8_t *)text);
}
}
/* USER CODE END 4 */
二、IIC通信-eeprom
原理图AT24C02
引脚配置
为什么要配置成output模式因为官方会提供一个i2c的库,可以直接用用的是软件IIC
不可用状态,用的软件IIC
之后直接生成就可
官方库移植
将这两个文件复制到bsp文件下面
At24c02手册
1k,2k是容量
一个总线上可以挂很多很多芯片
真题案例
实验现象
问题 ---按键没有用只显示1038
案例程序
#include "i2c - hal.h"官方给的参考程序的头文件有问题所以要改成这样
I2c.h
cpp
#ifndef __I2C_H
#define __I2C_H
#include "main.h"
void I2CStart(void);
void I2CStop(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(void);
void I2CSendNotAck(void);
void I2CSendByte(unsigned char cSendByte);
unsigned char I2CReceiveByte(void);
void I2CInit(void);
void eeprom_write(uchar addr,uchar dat);
uchar eeprom_read(uchar addr);
#endif
i2c.c
读的函数
cpp
//读的函数
uchar eeprom_read(uchar addr)
{
//正常代码
// uchar dat;
// I2CStart();//i2c开启
// I2CSendByte(0xa0);//联系芯片
// I2CWaitAck();
// I2CSendByte(addr);//传递的参数
// I2CWaitAck();
//
// //将真实的数据读回
// I2CStart();
// I2CSendByte(0xa1);
// I2CWaitAck();//发送完等待
// dat=I2CReceiveByte();
// I2CSendNotAck();
// I2CStop();
// return dat;//返回结果
uchar dat;
I2CStart();//i2c开启
I2CSendByte(0xa0);//联系芯片
I2CWaitAck();
I2CSendByte(addr);//传递的参数
I2CWaitAck();
I2CStop();
I2CStart();//i2c开启
I2CSendByte(0xa1);//联系芯片
I2CWaitAck();
dat=I2CReceiveByte();
I2CSendNotAck();
I2CStop();
return dat;//返回结果
}
写的函数
cpp
void eeprom_write(uchar addr,uchar dat)
{
I2CStart();//i2c开启
I2CSendByte(0xa0);//联系芯片
I2CWaitAck();//等待应答
I2CSendByte(addr);//传递的参数
I2CWaitAck();
I2CSendByte(dat);//数据发送给芯片
I2CWaitAck();
I2CStop();
}
main
cpp
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "led.h"
#include "lcd.h"
#include "stdio.h"
#include "interrupt.h"
#include "badc.h"
#include "i2c - hal.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
void key_proc(void);//按键的过程
void disp_proc(void);//显示界面的过程
extern struct keys key[];
extern uint frq1,frq2;//计算的到的回调值
extern float duty1,duty2;
uchar view=0;
uchar pa6_duty = 10;
uchar pa7_duty = 10;
/* USER CODE END PTD */
主函数
cpp
int main(void)
{
/* USER CODE BEGIN 2 */
LED_Disp(0x00);//LED初始化
LCD_Init();//LCD初始化
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
HAL_TIM_Base_Start_IT(&htim4); //定时器中断
HAL_TIM_PWM_Start(&htim16,TIM_CHANNEL_1);//打开pwm的输出通道
HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);//打开pwm的输通道
//打开定时器
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1); //定时器中断 频率测量捕获定时器开启
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1); //定时器中断
/* USER CODE END 2 */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE BEGIN 3 */
key_proc();
disp_proc();
// LED_Disp(0x02);
// HAL_Delay(500);
// LED_Disp(0x00);
// HAL_Delay(1000);
}
/* USER CODE END 3 */
}
按键的过程、参数显示界面
cpp
/* USER CODE BEGIN 4 */
void key_proc(void)//按键的过程
{
if(key[0].single_flag ==1)
{
view=!view;
key[0].single_flag=0;
}
if(key[1].single_flag ==1)//按键2按下一次加10%
{
pa6_duty+=10;
if(pa6_duty>=100) pa6_duty=10;
__HAL_TIM_SetCompare(&htim16,TIM_CHANNEL_1,pa6_duty);//设置比较
key[1].single_flag=0;
}
if(key[2].single_flag ==1)//按键3 按下一次加10%
{
pa7_duty+=10;
if(pa7_duty>=100) pa7_duty=10;
__HAL_TIM_SetCompare(&htim17,TIM_CHANNEL_1,pa7_duty);//设置比较
key[2].single_flag=0;
}
//显示按键频率 eeprom只能存一个8位,所以要将他拆成高八位和低八位
if(key[3].single_flag ==1)//按键3
{
uchar frq_h = frq1 >> 8;
uchar frq_l = frq1 & 0xff;
eeprom_write(1,frq_h);//写入高位
HAL_Delay(10);//太快会发不出去
eeprom_write(2,frq_l);//写入低8位
key[3].single_flag = 0;
}
}
void disp_proc(void)//显示界面的过程
{
if(view==0)
{
char text[30];
sprintf(text," Data ");
LCD_DisplayStringLine(Line1, (uint8_t *)text);
sprintf(text," FRQ1=%d ",frq1);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
sprintf(text," duty1=%.3f ",duty1);
LCD_DisplayStringLine(Line3, (uint8_t *)text);
sprintf(text," FRQ2=%d ",frq2);
LCD_DisplayStringLine(Line4, (uint8_t *)text);
sprintf(text," duty2=%.3f ",duty2);
LCD_DisplayStringLine(Line5, (uint8_t *)text);
//ADC显示 1 测量的是靠左的电位器
sprintf(text," V:=%.2f ",getADC(&hadc1));//在mx中配置了
LCD_DisplayStringLine(Line6, (uint8_t *)text);
//2
sprintf(text," V:=%.2f ",getADC(&hadc2));//在mx中配置了
LCD_DisplayStringLine(Line7, (uint8_t *)text);
uint eep_temp=(eeprom_read(1)<<8)+eeprom_read(2);//读取数据,高8位放第1位,低8位放2为
sprintf(text," FRQ_eep=%d ",eep_temp);//将存入的数据显示出来
LCD_DisplayStringLine(Line8, (uint8_t *)text);
}
if(view==1)//参数显示界面
{
char text[30];
sprintf(text," Para ");
LCD_DisplayStringLine(Line1, (uint8_t *)text);
sprintf(text," PA6:%d ",pa6_duty);
LCD_DisplayStringLine(Line3, (uint8_t *)text);
sprintf(text," PA7:%d ",pa7_duty);
LCD_DisplayStringLine(Line4, (uint8_t *)text);
//界面清理
sprintf(text," ");
LCD_DisplayStringLine(Line2, (uint8_t *)text);
sprintf(text," ");
LCD_DisplayStringLine(Line5, (uint8_t *)text);
}
}
/* USER CODE END 4 */
案例显现展示
三、uart
原理图
2022年1月~2月购买的可能会有硬件故障 --
官方给的代码的测试现象
cube配置
改为异步模式,同步模式其他端口被占用,串口参数设置,如果没有设置lcd的话他会默认PC4和PC5,所以需要手动更改
参数设置
波特率设置
根据题目要求设置
中断使能
之后生成代码即可
案例代码呈现
interrupt同上
main
cpp
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "led.h"
#include "lcd.h"
#include "stdio.h"
#include "interrupt.h"
#include "badc.h"
#include "i2c - hal.h"
#include "string.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
void key_proc(void);//按键的过程
void disp_proc(void);//显示界面的过程
extern struct keys key[];
extern uint frq1,frq2;//计算的到的回调值
extern float duty1,duty2;
uchar view=0;
uchar pa6_duty = 10;
uchar pa7_duty = 10;
/* USER CODE END PTD */
主函数
cpp
int main(void)
{
/* USER CODE BEGIN 2 */
LED_Disp(0x00);//LED初始化
LCD_Init();//LCD初始化
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
HAL_TIM_Base_Start_IT(&htim4); //定时器中断
HAL_TIM_PWM_Start(&htim16,TIM_CHANNEL_1);//打开pwm的输出通道
HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);//打开pwm的输通道
//打开定时器
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1); //定时器中断 频率测量捕获定时器开启
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1); //定时器中断
/* USER CODE END 2 */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
key_proc();
disp_proc();
//简单的发送
char temp[20];
sprintf(temp,"frq=%d\r\n",frq1); //打印频率再电脑
HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);
HAL_Delay(500);
}
/* USER CODE END 3 */
}
按键设置及界面显示
cpp
/* USER CODE BEGIN 4 */
void key_proc(void)//按键的过程
{
if(key[0].single_flag ==1)
{
view=!view;
key[0].single_flag=0;
}
if(key[1].single_flag ==1)//按键2按下一次加10%
{
pa6_duty+=10;
if(pa6_duty>=100) pa6_duty=10;
__HAL_TIM_SetCompare(&htim16,TIM_CHANNEL_1,pa6_duty);//设置比较
key[1].single_flag=0;
}
if(key[2].single_flag ==1)//按键3 按下一次加10%
{
pa7_duty+=10;
if(pa7_duty>=100) pa7_duty=10;
__HAL_TIM_SetCompare(&htim17,TIM_CHANNEL_1,pa7_duty);//设置比较
key[2].single_flag=0;
}
//显示按键频率 eeprom只能存一个8位,所以要将他拆成高八位和低八位
if(key[3].single_flag ==1)//按键3
{
uchar frq_h = frq1 >> 8;
uchar frq_l = frq1 & 0xff;
eeprom_write(1,frq_h);//写入高位
HAL_Delay(10);//太快会发不出去
eeprom_write(2,frq_l);//写入低8位
key[3].single_flag = 0;
}
}
void disp_proc(void)//显示界面的过程
{
if(view==0)
{
char text[30];
sprintf(text," Data ");
LCD_DisplayStringLine(Line1, (uint8_t *)text);
sprintf(text," FRQ1=%d ",frq1);
LCD_DisplayStringLine(Line2, (uint8_t *)text);
sprintf(text," duty1=%.3f ",duty1);
LCD_DisplayStringLine(Line3, (uint8_t *)text);
sprintf(text," FRQ2=%d ",frq2);
LCD_DisplayStringLine(Line4, (uint8_t *)text);
sprintf(text," duty2=%.3f ",duty2);
LCD_DisplayStringLine(Line5, (uint8_t *)text);
//ADC显示 1 测量的是靠左的电位器
sprintf(text," V:=%.2f ",getADC(&hadc1));//在mx中配置了
LCD_DisplayStringLine(Line6, (uint8_t *)text);
//2
sprintf(text," V:=%.2f ",getADC(&hadc2));//在mx中配置了
LCD_DisplayStringLine(Line7, (uint8_t *)text);
串口相关代码//
/
uint eep_temp=(eeprom_read(1)<<8)+eeprom_read(2);//读取数据,高8位放第1位,低8位放2为
sprintf(text," FRQ_eep=%d ",eep_temp);//将存入的数据显示出来
LCD_DisplayStringLine(Line8, (uint8_t *)text);
}
if(view==1)//参数显示界面
{
char text[30];
sprintf(text," Para ");
LCD_DisplayStringLine(Line1, (uint8_t *)text);
sprintf(text," PA6:%d ",pa6_duty);
LCD_DisplayStringLine(Line3, (uint8_t *)text);
sprintf(text," PA7:%d ",pa7_duty);
LCD_DisplayStringLine(Line4, (uint8_t *)text);
//界面清理
sprintf(text," ");
LCD_DisplayStringLine(Line2, (uint8_t *)text);
sprintf(text," ");
LCD_DisplayStringLine(Line5, (uint8_t *)text);
}
}
/* USER CODE END 4 */
现象效果展示
串口数据
lcd显示