本文会介绍oled的基本驱动,让其显示一些基础的东西,并且通过两个单片机来实现一个简单的pwm捕获功能(疫情原因没有信号发生,只能用一个单片机来执行输出)。先讲讲思路吧,我会先用一个单片机来输出一个稳定的pwm波,然后再对第二个单片机实现pwm波的捕获功能,最后连接oled模块实现数据的显示。在这里我使用的单片机为stm32rct6和stm32c6t6.
然后是时钟树配置
下面两个是对应的设置,我就不细说了。
接着就是定时器的配置了,为了方便观察,我把我的单片机上的led对应的灯的io口,让其为pwm波的输出口。在这里我的led是pA8,所以我选择tim1和通道一,打开内部时钟。
接下来就是pwm波的数据配置,为了方便观察,我设定的为周期1s,占空比50%,数据如下
最后生成工程,打开keil,在这个位置打开就欧克了。
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
/* USER CODE END 2 */
首先cubemx还是老样子,在这里我只打开了tim2的channel4,用于捕获。对应的引脚配置根据自己的来就可以了,这里我的io口是PB11,在后面再说如何连接。
接下来就是代码编写,如下图位置,都已经做了注释
/* USER CODE BEGIN PV */
unsigned char capture_flag=0;//电平变化次数
unsigned int capture_buf[3]= {0};
//存时间数据的数组,分别为存第一次上升时间,第一次下降时间,和第二次上升时间
double high_time=0;//存高电平时间
double low_time=0;//存低电平时间
double T=0;//周期
double f=0;//频率
double Duty=0;//占空比的值
/*已经用cubemx设置PSC为72-1,ARR是1000,也就是1ms计数一次*/
/* USER CODE END PV */
/* USER CODE BEGIN PFP */
void capture(void);//这里这个是一个函数声明,会用于下面的函数,到下面了再解析。
/* USER CODE END PFP */
然后我们在这个区域块,编写捕获函数
/* USER CODE BEGIN 4 */
void capture()
{
switch(capture_flag)
{
case 0:
capture_flag++;
//flag变为1后回到tim.c的文件里面去执行捕获的内容
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2, TIM_CHANNEL_4, TIM_INPUTCHANNELPOLARITY_RISING);
//检测到电平上升,开启上升沿捕获功能
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_4); //打开输入捕获
break;
case 4:
high_time = capture_buf[1]- capture_buf[0];
//高电平时间为第一次捕获下降沿的时间减去第一次上升沿的时闿
low_time= capture_buf[2]- capture_buf[1];
//低电平时间为第二次上升沿减去第一次下降沿的时闿
capture_flag = 0; //使其为0
break;
default:
break;
}
}
/* USER CODE END 4 */
接着打开Tim.c文件,我们要在这里实现完整的捕获过程,先进行一些基本定义声明。
/* USER CODE BEGIN 0 */
extern unsigned char capture_flag;//设置全部的一个flag方便两个.c使用
extern unsigned int capture_buf[3];//同理设置数组
void capture_timer(void);//声明捕捉函敿
//extern double T=0;//周期
//extern double f=0;//频率
//extern double Duty=0;//占空比
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)//执行的函敿
{
if(TIM2 == htim->Instance)
{
capture_timer();
}
}
/* USER CODE END 0 */
然后我们拉到最下面,写入这段代码
/* USER CODE BEGIN 1 */
void capture_timer()
{
switch(capture_flag)//main里面出来的时候flag是1
{
case 1:
{
capture_buf[0] = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_4);
//获取第一次上升电平的时间并且存储在数组1里面
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_4,TIM_ICPOLARITY_FALLING);
//把捕获设置为下降沿捕获
capture_flag++;//flag变成2
break;
}
case 2:
{
capture_buf[1] = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_4);
//获取第一次下降电平时间并且存储在数组2里面
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_4,TIM_ICPOLARITY_RISING);
//再设为上升沿捕获来获取第二次上升
capture_flag++;//flag变成3
break;
}
case 3:
{
capture_buf[2] = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_4);
//获取第二次上升电平时间并且存储在数组三里靿
HAL_TIM_IC_Stop_IT(&htim2,TIM_CHANNEL_4); //停止捕获
capture_flag++;//变为4返回原先main里面的switch
break;
}
}
}
/* USER CODE END 1 */
以上就是第二个单片机通过定时器实现的一个简单的pwm波的捕获,详细的内容大家可以看别的文章,在这里先大概说一下,其实就是打开一个定时器来计数,通过次数来计算时间的方式,最后存储到数组里面来实现数据捕获,详细的原理请大家去找别的博主,这里一定要先搞清楚定时器捕获的原理再进行编写。
接下来就是对oled驱动的重头戏了,其实oled驱动很简单,首先提醒大家在购买oled的时候尽量找商家要相关的驱动资料,我当初买的时候元旦放假,商家都休息了,我根本拿不到资料,最后是在网站上一个个找一个个试才成功的,相当浪费时间,有驱动文件真的真的会非常轻松!在这里我的oled是0.96寸的iic协议的。
然后考虑内容比较多,我会把四个文件放到别的地方去,使用的时候直接照搬就行了。
oled的驱动文件(原文的补充在这里)_ZHAOsir1118的博客-CSDN博客122https://blog.csdn.net/ZHAOsir1118/article/details/123013476?spm=1001.2014.3001.5502
然后是取模软件的下载,网上有很多,这里拿出一个我下的,取模也很简单,在这里我就不教学怎么使用了,网上的都教的很详细了https://blog.csdn.net/qq_43106548/article/details/119360520?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164520005116780271926529%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164520005116780271926529&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-2-119360520.pc_search_result_cache&utm_term=pctolcd2002%E4%B8%8B%E8%BD%BD&spm=1018.2226.3001.4187https://blog.csdn.net/qq_43106548/article/details/119360520?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164520005116780271926529%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164520005116780271926529&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-2-119360520.pc_search_result_cache&utm_term=pctolcd2002%E4%B8%8B%E8%BD%BD&spm=1018.2226.3001.4187
接下来就是cubemx的配置了,还是原先的地方,在这里只要打开iic就行了,同时注意sda和scl对应的io口
然后这里的I2C Speed Mode就是 IIC模式设置 ,主要为快速模式和标准模式。实际上也就是速率的选择。,这里我们是标准模式。I2C Clock Speed就是I2C的传输速率,默认为100KHz,基本上这里不需要改动什么,只要打开iic就行了。
接下来就是keil的代码编写
/* USER CODE BEGIN Includes */
#include "oled.h"
#include "stdio.h"
/* USER CODE END Includes */
/* USER CODE BEGIN 1 */
//在main的下面做如下定义
//在前面定义变量
float K1 = T;
float K2 =Duty;
float K3 = f;
uint8_t K1_1[10];
uint8_t K2_2[10];
uint8_t K3_3[10];
/* USER CODE END 1 */
显示的部分我们放在while循环里面
OLED_Refresh();
//这个refresh很重要,没有他你的显示基本是不正常的
sprintf(K1_1, "fre:%.2f", K1);//输出频率
sprintf(K2_2, "duty:%.4f", K2);//输出占空比
sprintf(K3_3, "T:%.4f", K3);//输出周期
OLED_ShowString(0,0,K1_1,16,1);//这个是oled驱动里面的,是显示位置的一个函数,
OLED_ShowString(0,15,K2_2,16,1);//格式是(x轴,y轴,显示变量,16,1)
OLED_ShowString(0,30,K3_3,16,1);//详细的可以查看驱动文件,不细说了,这些函数基本都是套用
然后代码的编写就欧克了。
首先是第一个单片机,我们定义的是PA8口的,并且周期1s,占空比50,然后led就会一闪一闪的,,说明单片机一输出了pwm波,然后我们再连接oled和第二个单片机,连接方式为vcc和gnd连接,然后oled的scl连接PB6,我的cubemx里面pb6为scl,然后oled的sda连接单片机的PB7,然后把keil烧录进去,reset下,就可以看到如下的照片
然后我们这个时候要把第一个单片机输出pwm的io口,和第二个单片机的pwm波的接收io口连接,这里回应前面说的,在这里我的第一个单片机设置的是PA8输出,第二个设置的是PB11接收,那么把这两个对应的连接就ok了,同时要供地,再用一根杜邦线连接各自的gnd。经过测试,可以得到下面的图片
可以看到误差还是可以接受的,(本人还是个小白,编写的东西可能不够完整,数据偏差还是比较大的,加上连接等等问题,还会出现很多不稳定的情况,照片里面的其实是比较稳定的时候了),然后本文只是简单介绍和使用了oled显示变量的功能(IIC),如果是oled的基本显示的话,取模的教程在网上还是比较多的,教程也非常详细,在这里我就只介绍变量之类的显示了。
那到这就结束了,谢谢各位。