打印
[其他ST产品]

STM32+12864实现RGB灯亮度的菜单调节

[复制链接]
楼主: 和下土
手机看帖
扫描二维码
随时随地手机跟帖
21
和下土|  楼主 | 2023-9-29 19:00 | 只看该作者 回帖奖励 |倒序浏览
这一个函数采用for循环嵌套的方法实现。变量i控制当前写入的是第几组,变量n控制当前写的是第几列。0xb0、0x00、0x10等属于OLED12864芯片定义好的指令,想要了解的朋友可以自行查阅数据手册。

使用特权

评论回复
22
和下土|  楼主 | 2023-9-29 19:00 | 只看该作者
了解了OLED12864如何显示内容。我们就可以在OLED12864上显示出我们想要的内容了。但是直接修改OLED_GRAM[][]数组中的值非常麻烦。所以我们可以利用一些专门的函数来帮助我们。接下来介绍用于实现汉字显示的函数。

使用特权

评论回复
23
和下土|  楼主 | 2023-9-29 19:00 | 只看该作者
void OLED_ShowChinese(u8 x,u8 y,u8 num,u8 size1)
{
        u8 i,m,n=0,temp,chr1;
        u8 x0=x,y0=y;
        u8 size3=size1/8;
        while(size3--)//行数控制
        {
                chr1=num*size1/8+n;
                n++;
                        for(i=0;i<size1;i++)//列数控制
                        {
                                if(size1==16)
                                                {temp=Hzk1[chr1][i];}//调用16*16字体
                                else if(size1==24)
                                                {temp=Hzk2[chr1][i];}//调用24*24字体
                                else if(size1==32)      
                                                {temp=Hzk3[chr1][i];}//调用32*32字体
                                else if(size1==64)
                                                {temp=Hzk4[chr1][i];}//调用64*64字体
                                else return;
                                                       
                                                for(m=0;m<8;m++)//把temp变量的值赋值给
                                                        {
                                                                if(temp&0x01)OLED_DrawPoint(x,y);
                                                                else OLED_ClearPoint(x,y);
                                                                temp>>=1;
                                                                y++;
                                                        }
                                                        x++;
                                                        if((x-x0)==size1)
                                                        {x=x0;y0=y0+8;}
                                                        y=y0;
                         }
        }
}

使用特权

评论回复
24
和下土|  楼主 | 2023-9-29 19:00 | 只看该作者
由于 OLED12864内部没有中文字库,所以实现需要利用取模软件对汉字进行取模。再将取模的结果存放于一个二维数组中。本例程以中文字模存放于Hzk?数组中为例。

使用特权

评论回复
25
和下土|  楼主 | 2023-9-29 19:00 | 只看该作者
这个函数有四个形参,前两个代表了需要写入汉字的起始坐标(x,y),第三个形参num代表储存在Hzk?[][]数组中的下标。第四个形参sizel代表显示汉字的大小,可输入的值有:16、24、32、64,数字代表汉字需要占据的长宽数据。如输入16,则表示汉字的占据了横向16个,纵向16个,即16*16个像素的位置。

使用特权

评论回复
26
和下土|  楼主 | 2023-9-29 19:00 | 只看该作者
函数内部变量,x0、y0分别记录了汉字起始的X、Y坐标,size3由size1/8得来。用于控制汉字的纵向长度。这一点有些朋友可能不太理解,我做个简单的说明。在前面的讲解中我提到,OLED12864在纵向的64个点被分成了8组。每次写入时都是8bit的数据进行写入。所以我们将其除以8,实现控制纵向上需要写入多少个组。num用于控制需要HZK?[][]数组的下标。

使用特权

评论回复
27
和下土|  楼主 | 2023-9-29 19:01 | 只看该作者
该程序的实现同样使用了循环的嵌套,最外层的while循环的判断条件中写入了size3–,实现纵向控制。内部嵌套了以个for循环。用于写入每一祖中的每一列的值。汉字的大小由size1控制。所以for循环运行的条件为 i<size1。for循环内部的if—else语句则用于控制需要写入不同的大小时汉字所对应的数组。将数组中的值赋给变量temp。由于数组中存放的值为8个二进制位。所以进入一个重复8次的循环。将temp的值和0X01相与。即如果temp中的最低位为0时,执行OLED_DrawPoint(x,y);,否则执行 OLED_ClearPoint(x,y);。完成后将temp的值右移一位。重复上述内容。OLED_DrawPoint(x,y)函数可简单理解为显示OLED12864上的(x,y)坐标对应的点。而OLED_ClearPoint(x,y);代表清除该点。

使用特权

评论回复
28
和下土|  楼主 | 2023-9-29 19:01 | 只看该作者
除了汉字显示,还有另一个函数用于显示数字,英文等,原理类似,就不再分析,感兴趣的朋友可以自己去研究研究。

使用特权

评论回复
29
和下土|  楼主 | 2023-9-29 19:01 | 只看该作者
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size1)
{
        u8 i,m,temp,size2,chr1;
        u8 y0=y;
        size2=(size1/8+((size1%8)?1:0))*(size1/2);  //得到字体一个字符对应点阵集所占的字节数
        chr1=chr-' ';  //计算偏移后的值
        for(i=0;i<size2;i++)
        {
                if(size1==12)
        {temp=asc2_1206[chr1][i];} //调用1206字体
                else if(size1==16)
        {temp=asc2_1608[chr1][i];} //调用1608字体
                else if(size1==24)
        {temp=asc2_2412[chr1][i];} //调用2412字体
                else return;
                                for(m=0;m<8;m++)           //写入数据
                                {
                                        if(temp&0x80)OLED_DrawPoint(x,y);
                                        else OLED_ClearPoint(x,y);
                                        temp<<=1;
                                        y++;
                                        if((y-y0)==size1)
                                        {
                                                y=y0;
                                                x++;
                                                break;
                                  }
                        }
  }
}

使用特权

评论回复
30
和下土|  楼主 | 2023-9-29 19:01 | 只看该作者
STM32PWM输出
STM32PWM简介
PWM是英文“ Pulse Width Modulation” 的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。可以简单的理解为占空比。即一段限定的时间内,低电平占据的百分比是多少。其作用主要用于电机调速与LED的亮度控制。

使用特权

评论回复
31
和下土|  楼主 | 2023-9-29 19:01 | 只看该作者
STM32PWM呼吸灯实验实现
STM32中共有三类定时器,包括基本定时器——TIM6和TIM7,通用定时器TIM2、TIM3、TIM4、TIM5,高级定时器TIM1、TIM8。除了基本定时器以外都可以用于PWM输出。其中通用定时器可以输出4路,高级定时器可以输出8路。
我们实验中采用的是TIM3。对应的引脚为PB0、PB1、PB5。其中因为PB5属于复用功能。所以在使用程序时需要先进行重映射。
STM32的固件库中有四个和定时器相关的库函数。其中使用PWM需要配置其中的两个即可: 时 基 初 始 化 结 构 体 TIM_TimeBaseInitTypeDef 、 输 出 比 较 初 始 化 结 构 体 TIM_OCInitTypeDef。具体如何配置不做介绍,感兴趣的朋友可以直接看我最后放上来的程序。

使用特权

评论回复
32
和下土|  楼主 | 2023-9-29 19:01 | 只看该作者
在配置完成TIM的配置之后,我们只需要直接将需要写入的PWM值写入到对应的CCR寄存器中即可。为了方便使用,采用函数的方式进行写入

使用特权

评论回复
33
和下土|  楼主 | 2023-9-29 19:01 | 只看该作者
void SetColorValue(uint8_t r,uint8_t g,uint8_t b)
{
        //根据颜色值修改定时器的比较寄存器值
        COLOR_TIMx->COLOR_RED_CCRx = r;       
        COLOR_TIMx->COLOR_GREEN_CCRx = g;                
        COLOR_TIMx->COLOR_BLUE_CCRx = b;       
}

使用特权

评论回复
34
和下土|  楼主 | 2023-9-29 19:02 | 只看该作者
菜单
菜单的内容设计
设计菜单首先需要分清楚三件事:1.可用于交互的手段 2.需要用于调节的内容 3.显示选中的方式 。在野火的霸道V2开发板上可用于交互的有两个实体按键和一个电容按键。但是经过测试电容按键的灵敏度简直令人感动到落泪。所以使用两个按键作为交互手段。在该实验中我们的任务设定是需要能够分别调节RGB灯的亮度。所以需要调节的内容就是亮度和LED灯的颜色。显示选中方式采用了在当前选中颜色的亮度后面画圆的方法。板子上的按键一用于选择不同颜色的LED灯。按键二用于调节当前选中的LED灯的亮度。

使用特权

评论回复
35
和下土|  楼主 | 2023-9-29 19:02 | 只看该作者
菜单的程序实现
菜单的内容分为三部分:灯的颜色、灯的亮度以及选中后显示的圆圈。因此,我写了一个初始话函数,让我们要内容显示在OLED12864上。

使用特权

评论回复
36
和下土|  楼主 | 2023-9-29 19:02 | 只看该作者
void caidan_display(uint8_t red,uint8_t green,uint8_t blue)
{
       
                OLED_Str_Chinese(2,0,0);
                OLED_Str_Chinese(3,0,3);
                OLED_Str_Chinese(2,1,1);
                OLED_Str_Chinese(3,1,3);
                OLED_Str_Chinese(2,2,2);
                OLED_Str_Chinese(3,2,3);
                OLED_ShowNum(68,0,red,2,12);
                OLED_ShowNum(68,18,green,2,12);
                OLED_ShowNum(68,34,blue,2,12);


                OLED_Refresh();
}

使用特权

评论回复
37
和下土|  楼主 | 2023-9-29 19:02 | 只看该作者
void OLED_Str_Chinese(u8 x,u8 y,u8 num)
{
        x = x*16;
        y = y*16;
        u8 size1 = 16;
        u8 i,m,n=0,temp,chr1;
        u8 x0=x,y0=y;
        u8 size3=size1/8;
        while(size3--)//行数控制
        {
                chr1=num*size1/8+n;
                n++;
                        for(i=0;i<size1;i++)//列数控制
                        {
                                                temp=Chidan[chr1][i];                                               
                                                for(m=0;m<8;m++)//把temp变量的值赋值给
                                                        {
                                                                if(temp&0x01)OLED_DrawPoint(x,y);
                                                                else OLED_ClearPoint(x,y);
                                                                temp>>=1;
                                                                y++;
                                                        }
                                                        x++;
                                                        if((x-x0)==size1)
                                                        {x=x0;y0=y0+8;}
                                                        y=y0;
                         }
        }
}

使用特权

评论回复
38
和下土|  楼主 | 2023-9-29 19:02 | 只看该作者
第一个函数 caidan_display();用于显示出菜单上的红灯、绿灯、蓝灯。以及对应的亮度。其中有三个形参。分别对应在红灯、绿灯、蓝灯后面现实的内容。第二个函数OLED_Str_Chinese,是 OLED_ShowChinese(u8 x,u8 y,u8 num,u8 size1)函数做了一些修改后得到的,原理不变,变得地方有两个。1.由于在该函数中使用的字体都为16*16的格式。所以我在函数内部做了一些计算。在输入时只需要写入第几行第几列显示汉字即可,不需要在写入横向和纵向的像素点位置。2.由于OLED12864内部没有带汉字字库。所以需要将要使用的汉字的取模,并放入数组中。Chidan[chr1][i]数组,就是我用来存放汉字取模结果的数组。

使用特权

评论回复
39
和下土|  楼主 | 2023-9-29 19:02 | 只看该作者
##总程序
int main(void)
{
        uint8_t red = 0,green = 0,bull = 0;
        uint8_t value1 = 0,value2 = 0,value3 = 0;
        uint8_t key = -1;//0表示选中颜色,1表示选中PWM
        uint8_t i = 10;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
        KEY_GPIO_Config();
        delay_init();
        OLED_Cofing();
        caidan_display(00,00,00);
        COLOR_TIMx_LED_Init();
        while(1)
        {
                       
                if(Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN))//按下按键1,用于改变选中目标
                        {       
                                OLED_Clear();       
                                key++;
                                key = key % 3;       
                                key_RGB_chang(key);
                        }
                if(Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN))//按下按键2,用于改变值
                        {       
                                OLED_Clear();                               
                                if(key==0)
                                        {
                                                red = red + 25;
                                                red = red % 250;
                                                value1 = (++value1) %10;
                                        }
                                else if(key==1)
                                        {
                                                green = green + 25;
                                                green = green % 250;
                                                value2 = (++value2) %10;
                                        }
                                else if(key==2)
                                        {
                                                bull = bull + 25;
                                                bull = bull % 250;
                                                value3 = (++value3) %10;
                                        }       

                                //key_RGB_chang(key);
                        }
                caidan_display(value1,value2,value3);
                SetColorValue(red,green,bull);
                OLED_Refresh();
        }
       
       
}

使用特权

评论回复
40
和下土|  楼主 | 2023-9-29 19:02 | 只看该作者
在main函数里,定义了一个变量key用来代表当前选中的颜色定义了red、bull 、green三个变量用于亮度的控制,value1—value3用于存放OLED上显示的颜色对应的亮度。当按键1被按下时,通过key++改变当前选中的颜色。并利用key_RGB_chang(key);函数用于在当前选中的函数后面画圈,代表当前被选中。当按键二被按下后,会进入一个if语句进行分类处理。分类的依据是key的值,即当前选中的颜色。按钮二被按下以后用于存放亮度的变量加25(因为PWM分为了255级。程序中需要实现的是10级调节亮度,255/10后得25余5).用于显示在OLED上的value变量也进行加1。实现OLED显示和实际亮度的同一。两个if语句处理完之后。把if语句里面修改的变量值写入函数中。实现菜单显示的改变和RGB灯亮度的调节。]

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则