zoukankan      html  css  js  c++  java
  • STM32F103+OLED绘制曲线

    STM32F103+OLED曲线绘制
    从本文的标题便能看出,此次分享的内容是以STM32F103C8T6芯片为控制核心,OLED则为0.96寸I2C通信的4针类型。其实OLED的类型不是重点,各种类型的操作基本大同小异,无非是读写通信方式的不同而已,接下来为大家详细介绍OLED屏除显示汉字、字符、数字外,绘图功能的实现,大体分为硬件连接与软件代码编写两大部分。

    硬件连接部分
    0.96寸OLED屏如下图所示:


    根据上图我们可以看到,这个型号的OLED屏只有4个引脚,真正与MCU通信的信号线才2根,比较适合于通用I/O口资源较少的控制芯片。在本文中OLED与STM32F103C8T6芯片的硬件I2C相连接: PB6 – SCL;PB7 – SDA 。

    软件程序部分
    1. OLED I2C通信代码

    void I2C_Configuration(void)
    {
    I2C_InitTypeDef I2C_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

    /*STM32F103C8T6芯片的硬件I2C: PB6 -- SCL; PB7 -- SDA */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;//I2C必须开漏输出
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    I2C_DeInit(I2C1);//使用I2C1
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0x30;//主机的I2C地址,随便写的
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 400000;//400K

    I2C_Cmd(I2C1, ENABLE);
    I2C_Init(I2C1, &I2C_InitStructure);
    }


    /**
    * @brief I2C_WriteByte,向OLED寄存器地址写一个byte的数据
    * @param addr:寄存器地址
    * data:要写入的数据
    * @retval 无
    */
    void I2C_WriteByte(uint8_t addr,uint8_t data)
    {
    while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));

    I2C_GenerateSTART(I2C1, ENABLE);//开启I2C1
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));/*EV5,主模式*/

    I2C_Send7bitAddress(I2C1, OLED_ADDRESS, I2C_Direction_Transmitter);//器件地址 -- 默认0x78
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    I2C_SendData(I2C1, addr);//寄存器地址
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_SendData(I2C1, data);//发送数据
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    I2C_GenerateSTOP(I2C1, ENABLE);//关闭I2C1总线
    }


    /**
    * @brief WriteCmd,向OLED写入命令
    * @param I2C_Command:命令代码
    * @retval 无
    */
    void WriteCmd(unsigned char I2C_Command)//写命令
    {
    I2C_WriteByte(0x00, I2C_Command);
    }


    /**
    * @brief WriteDat,向OLED写入数据
    * @param I2C_Data:数据
    * @retval 无
    */
    void WriteDat(unsigned char I2C_Data)//写数据
    {
    I2C_WriteByte(0x40, I2C_Data);
    }


    /**
    * @brief OLED_Init,初始化OLED
    * @param 无
    * @retval 无
    */
    void OLED_Init(void)
    {
    DelayMs(100); //这里的延时很重要

    WriteCmd(0xae);//--turn off oled panel"关闭led面板"
    WriteCmd(0x00);//---set low column address设置低列地址
    WriteCmd(0x10);//---set high column address设置高列地址
    WriteCmd(0x40);//--set start line address设置起始地址线 Set Mapping RAM Display Start Line (0x00~0x3F)
    WriteCmd(0x81);//--set contrast control register设置对比度控制寄存器
    WriteCmd(0xcf); // Set SEG Output Current Brightness设置亮度控制寄存器
    WriteCmd(0xa1);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
    WriteCmd(0xc8);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
    WriteCmd(0xa6);//--set normal display
    WriteCmd(0xa8);//--set multiplex ratio(1 to 64)设置多路复用
    WriteCmd(0x3f);//--1/64 duty
    WriteCmd(0xd3);//-set display offset Shift Mapping RAM Counter设置显示的偏移映射内存计数器 (0x00~0x3F)
    WriteCmd(0x00);//-not offset取消偏移补偿
    WriteCmd(0xd5);//--set display clock divide ratio/oscillator frequency设置显示时钟分频比/振荡器频率
    WriteCmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec设置分离比例,时钟设置为100帧/秒
    WriteCmd(0xd9);//--set pre-charge period预充电时间
    WriteCmd(0xf1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock预充电15钟及放电1时钟
    WriteCmd(0xda);//--set com pins hardware configurationCOM引脚设置硬件配置
    WriteCmd(0x12);
    WriteCmd(0xdb);//--set vcomh设置VCOM电平
    WriteCmd(0x40);//Set VCOM Deselect Level取消设置VCOM电平
    WriteCmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)设置页面寻址模式(0x00 /头/ 0x02)
    WriteCmd(0x02);//
    WriteCmd(0x8d);//--set Charge Pump enable/disable设置电荷泵启用/禁用
    WriteCmd(0x14);//--set(0x10) 设为0x10失能
    WriteCmd(0xa4);// Disable Entire Display On (0xa4/0xa5)禁用整个显示
    WriteCmd(0xa6);// Disable Inverse Display On (0xa6/a7) 禁用反显示
    WriteCmd(0xaf);//--turn on oled panel打开led面板

    }


    2.OLED的相关操作函数

    2.1.基础函数

    /**
    * @brief OLED_SetPos,设置光标
    * @param x,光标x位置
    * y,光标y位置
    * @retval 无
    */
    void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标
    {
    WriteCmd(0xb0+y);
    WriteCmd(((x&0xf0)>>4)|0x10);
    WriteCmd((x&0x0f)|0x01);
    }

    /**
    * @brief OLED_Fill,填充整个屏幕
    * @param fill_Data:要填充的数据
    * @retval 无
    */
    void OLED_Fill(unsigned char fill_Data)//全屏填充
    {
    unsigned char m,n;
    for(m=0;m<8;m++)
    {
    WriteCmd(0xb0+m); //page0-page1
    WriteCmd(0x00); //low column start address
    WriteCmd(0x10); //high column start address
    for(n=0;n<128;n++)
    {
    WriteDat(fill_Data);
    }
    }
    }

    /**
    * @brief OLED_CLS,清屏
    * @param 无
    * @retval 无
    */
    void OLED_CLS(void)//清屏
    {
    OLED_Fill(0x00);
    }


    /**
    * @brief OLED_ON,将OLED从休眠中唤醒
    * @param 无
    * @retval 无
    */
    void OLED_ON(void)
    {
    WriteCmd(0X8D); //设置电荷泵
    WriteCmd(0X14); //开启电荷泵
    WriteCmd(0XAF); //OLED唤醒
    }


    /**
    * @brief OLED_OFF,让OLED休眠 -- 休眠模式下,OLED功耗不到10uA
    * @param 无
    * @retval 无
    */
    void OLED_OFF(void)
    {
    WriteCmd(0X8D); //设置电荷泵
    WriteCmd(0X10); //关闭电荷泵
    WriteCmd(0XAE); //OLED休眠
    }


    /**
    * @brief OLED_ShowStr,显示codetab.h中的ASCII字符,有6*8和8*16可选择
    * @param x,y : 起始点坐标(x:0~127, y:0~7);
    * ch[] :- 要显示的字符串;
    * TextSize : 字符大小(1:6*8 ; 2:8*16)
    * @retval 无
    */
    void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
    {
    unsigned char c = 0,i = 0,j = 0;
    switch(TextSize)
    {
    case 1:
    {
    while(ch[j] != '')
    {
    c = ch[j] - 32;
    if(x > 126)
    {
    x = 0;
    y++;
    }
    OLED_SetPos(x,y);
    for(i=0;i<6;i++)
    WriteDat(F6x8[c][i]);
    x += 6;
    j++;
    }
    }break;
    case 2:
    {
    while(ch[j] != '')
    {
    c = ch[j] - 32;
    if(x > 120)
    {
    x = 0;
    y++;
    }
    OLED_SetPos(x,y);
    for(i=0;i<8;i++)
    WriteDat(F8X16[c*16+i]);
    OLED_SetPos(x,y+1);
    for(i=0;i<8;i++)
    WriteDat(F8X16[c*16+i+8]);
    x += 8;
    j++;
    }
    }break;
    }
    }

    /**
    * @brief OLED_ShowCN,显示codetab.h中的汉字,16*16点阵
    * @param x,y: 起始点坐标(x:0~127, y:0~7);
    * N:汉字在codetab.h中的索引
    * @retval 无
    */
    void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
    {
    unsigned char wm=0;
    unsigned int adder=32*N;
    OLED_SetPos(x , y);
    for(wm = 0;wm < 16;wm++)
    {
    WriteDat(F16x16[adder]);
    adder += 1;
    }
    OLED_SetPos(x,y + 1);
    for(wm = 0;wm < 16;wm++)
    {
    WriteDat(F16x16[adder]);
    adder += 1;
    }
    }

    /**
    * @brief OLED_DrawBMP,显示BMP位图
    * @param x0,y0 :起始点坐标(x0:0~127, y0:0~7);
    * x1,y1 : 起点对角线(结束点)的坐标(x1:1~128,y1:1~8)
    * @retval 无
    */
    void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
    {
    unsigned int j=0;
    unsigned char x,y;

    if(y1%8==0)
    y = y1/8;
    else
    y = y1/8 + 1;
    for(y=y0;y<y1;y++)
    {
    OLED_SetPos(x0,y);
    for(x=x0;x<x1;x++)
    {
    WriteDat(BMP[j++]);
    }
    }
    }

    2.2.描点函数
    入口参数:
    x:点的x坐标;
    y:点的y坐标;
    t:点的状态;“0”代表暗,“1”代表亮

    void OLED_DrawDot(unsigned char x,unsigned char y,unsigned char t)
    {
    unsigned char pos,bx,temp=0;
    if(x>127||y>63) return;
    pos=(y)/8;
    bx=y%8;
    temp=1<<(bx);
    if(t) OLED_GRAM[x][pos]|=temp;
    else OLED_GRAM[x][pos]&=~temp;
    OLED_Refresh_Gram();
    }

    2.3.连线函数
    入口参数:
    x1:起点的x坐标;
    y1:起点的y坐标;
    x2:终点的x坐标;
    y2:终点的y坐标;

    void LCD_DrawLine(unsigned int x1, unsigned int y1, unsigned int x2,unsigned int y2)
    {
    unsigned int t;
    int xerr=0,yerr=0,delta_x,delta_y,distance;
    int incx,incy,uRow,uCol;
    delta_x=x2-x1; //计算坐标增量
    delta_y=y2-y1;
    uRow=x1;
    uCol=y1;
    if(delta_x>0)incx=1; //设置单步方向
    else if(delta_x==0)incx=0;//垂直线
    else {incx=-1;delta_x=-delta_x;}
    if(delta_y>0)incy=1;
    else if(delta_y==0)incy=0;//水平线
    else{incy=-1;delta_y=-delta_y;}
    if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴
    else distance=delta_y;
    for(t=0;t<=distance+1;t++ )//画线输出
    {
    OLED_DrawDot(uRow,uCol,1);//画点
    xerr+=delta_x ;
    yerr+=delta_y ;
    if(xerr>distance)
    {
    xerr-=distance;
    uRow+=incx;
    }
    if(yerr>distance)
    {
    yerr-=distance;
    uCol+=incy;
    }
    }
    }

    最后实际运行效果图如下:

    详细程序如下

    1 OLED I2C通信代码

    2.OLED的相关操作函数

    2.1.基础函数

    2.2.描点函数
    入口参数:
    x:点的x坐标;
    y:点的y坐标;
    t:点的状态;“0”代表暗,“1”代表亮

    2.3.连线函数
    入口参数:
    x1:起点的x坐标;
    y1:起点的y坐标;
    x2:终点的x坐标;
    y2:终点的y坐标;



  • 相关阅读:
    BadUSB 利用
    java 将函数作为参数传递
    odoo12 修行提升篇之 常用的高阶函数 (二)
    odoo12 修行提升篇之 异步定时任务 (一)
    odoo12 修行基础篇之 利用kanban做分析 点击跳转分析模型列表 (九)
    odoo12 修行基础篇之 kanban (八)
    odoo12 修行基础篇之 记录批处理 (七)
    odoo12 修行基础篇之 列表的筛选和分组 (六)
    odoo12 修行基础篇之 添加记录编码 (五)
    odoo12 修行基础篇之 添加工作流和操作记录 (四)
  • 原文地址:https://www.cnblogs.com/laoxiongzhijia/p/14622037.html
Copyright © 2011-2022 走看看