最近通过B站下载到“老刘爱鼓捣”的开源资料,是基于51单片机+OLED做的示波器,自己在复现过程中也付出了许多时间和经济成本,现将所学程序中的知识总结如下:

1、如果有需要资料,可自行B站搜索,如也要复现则首先建议直接买51开发板,加上外围器件,我自己买51芯片焊接时,容易出现无法烧写程序和OLED显示屏不亮的情况。

2、通过EEProm 储存 读取设定参数,并且将检查合法性作为一个函数,统一检查各参数。

bit Save_Options()
{uint8 ops[15];uint8 *p;check_Options();p = ops;*p++ = Lsb >> 8;       //дÈëLsb¸ß8λ uint16*p++ = Lsb;            //дÈëLsbµÍ8λ*p++ = PlotMode;       //дÈë»æͼģʽ bit*p++ = ScaleH;         //дÈëʱ¼äÇø¼ä char*p++ = ScaleV_Auto;    //¶ÁÈ¡×Ô¶¯Á¿³Ì±êÖ¾ bit*p++ = RulerVMax >> 8; //дÈë×ÝÖáµçѹ¸ß8λ int16*p++ = RulerVMax;      //дÈë×ÝÖáµçѹµÍ8λ*p++ = RulerVMin >> 8; //дÈë×ÝÖáµçѹ¸ß8λ int16*p++ = RulerVMin;      //дÈë×ÝÖáµçѹµÍ8λ*p++ = TriLevel >> 8;  //дÈë´¥·¢Öµ¸ß8λ int16*p++ = TriLevel;       //дÈë´¥·¢ÖµµÍ8λ*p++ = TriMode;        //дÈë´¥·¢·½Ê½ int8*p++ = TriSlope;       //дÈë´¥·¢·½Ïò bit*p++ = WaveScroll;     //дÈ벨Ðιö¶¯±êÖ¾ bit*p = OLED_Brightness;  //дÈëOLEDÁÁ¶È uint8//    printf("Lsb=%hu\r\n",Lsb);// printf("DrawMode=%X\r\n",PlotMode);//    printf("ScaleH=%bd\r\n",ScaleH);//   printf("ScaleV_Auto=%X\r\n",ScaleV_Auto);//  printf("RulerVMax=%hd\r\n",RulerVMax);// printf("RulerVMin=%hd\r\n",RulerVMin);// printf("TriLevel=%hd\r\n",TriLevel);//   printf("TriMode=%bd\r\n",TriMode);// printf("TriSlope=%X\r\n",TriSlope);//    printf("WaveScroll=%X\r\n",WaveScroll);//    printf("OLED_Brightness=%bu\r\n",OLED_Brightness);// printf("\r\n");return EEPROM_Save(ops, sizeof(ops) / sizeof(ops[0]));
}
void Read_Options()
{uint8 ops[15];uint8 *p;p = ops;EEPROM_Read(ops, sizeof(ops) / sizeof(ops[0]));Lsb = *p++;           //¶ÁÈ¡Lsb¸ß8λ uint16Lsb <<= 8;            //½«µÍ8λÒƵ½¸ß°ËλLsb |= *p++;          //¶ÁÈ¡LsbµÍ8λPlotMode = *p++;      //¶ÁÈ¡»æͼģʽ bitScaleH = *p++;        //¶Áȡʱ¼äÇø¼ä charScaleV_Auto = *p++;   //¶ÁÈ¡×Ô¶¯Á¿³Ì±êÖ¾ bitRulerVMax = *p++;     //¶ÁÈ¡×ÝÖáµçѹ×î´óÖµ¸ß8λ int16RulerVMax <<= 8;      //½«µÍ8λÒƵ½¸ß°ËλRulerVMax |= *p++;    //¶ÁÈ¡×ÝÖáµçѹ×î´óÖµµÍ8λRulerVMin = *p++;     //¶ÁÈ¡×ÝÖáµçѹ×îС¸ß8λ int16RulerVMin <<= 8;      //½«µÍ8λÒƵ½¸ß°ËλRulerVMin |= *p++;    //¶ÁÈ¡×ÝÖáµçѹ×îСµÍ8λTriLevel = *p++;      //¶ÁÈ¡´¥·¢Öµ¸ß8λ int16TriLevel <<= 8;       //½«µÍ8λÒƵ½¸ß°ËλTriLevel |= *p++;     //¶ÁÈ¡´¥·¢ÖµµÍ8λTriMode = *p++;       //¶ÁÈ¡´¥·¢·½Ê½ int8TriSlope = *p++;      //¶ÁÈ¡´¥·¢·½Ïò bitWaveScroll = *p++;    //¶ÁÈ¡²¨Ðιö¶¯±êÖ¾ bitOLED_Brightness = *p; //¶ÁÈ¡OLEDÁÁ¶È uint8check_Options(); //¼ì²éÑ¡ÏîºÏ·¨ÐÔ//   printf("Lsb=%hu\r\n",Lsb);// printf("DrawMode=%X\r\n",PlotMode);//    printf("ScaleH=%bd\r\n",ScaleH);//   printf("ScaleV_Auto=%X\r\n",ScaleV_Auto);//  printf("RulerVMax=%hd\r\n",RulerVMax);// printf("RulerVMin=%hd\r\n",RulerVMin);// printf("TriLevel=%hd\r\n",TriLevel);//   printf("TriMode=%bd\r\n",TriMode);// printf("TriSlope=%X\r\n",TriSlope);//    printf("WaveScroll=%X\r\n",WaveScroll);//    printf("OLED_Brightness=%bu\r\n",OLED_Brightness);// printf("\r\n");
}

数组加指针配合,指向数组的指针。

 EEPROM_Read(ops, sizeof(ops) / sizeof(ops[0]));

3、将全局的变量、标志位、数组都放在global.h中,在各个文件中包含该头文件。

4、51单片机的关键字

bit                 位标量声明                 声明一个位标量或位类型的函数

sbit                 位标量声明                 声明一个可位寻址变量

sfr                特殊功能寄存器声明  声明一个特殊功能寄存器

sfr16             特殊功能寄存器声明  声明一个16位的特殊功能寄存器

关键字参考:https://blog.csdn.net/s3olo/article/details/7712586

关键字code是51单片机特有关键字,用unsigned int 或signed char等定义的变量都存储在单片机的RAM中,程序中可以随意更改这些变量的值。而运用code关键字修饰下定义的变量,比如unsigned char code i;,它们则存储在单片机程序存储空间FLASH中,节省单片机RAM资源,但在程序中不能更改这些变量的值。————————————————原文链接:https://blog.csdn.net/m0_46559794/article/details/108006698

uint16 *GetBGV(void)
{uint16 *BGV;BGV = (uint16 code *)BGV_ADR;return BGV;
}

以上程序取BGV寄存器中储存的参考电压数据。

5、OLED的显示操作 在该文件中总结了OLED写数据、写命令,画点、划线、画图的库,如下两个函数是OLED操作最底层函数,其他画点、画线、画字符串、写数字都是存在一个数组buf中,遍历OLED所有点,调用下列函数最终实现绘制。

void OLED_Write_Command(uint8 dat)
{uint8 i;OLED_DC_Clr();OLED_CS_Clr();for (i = 0; i < 8; i++){OLED_SCLK_Clr();if (dat & 0x80) //ÅжÏÊý¾Ý×î¸ßλÊÇ1»¹ÊÇ0{OLED_SDIN_Set();}elseOLED_SDIN_Clr();OLED_SCLK_Set();dat <<= 1;}OLED_CS_Set();//    OLED_DC_Set();
}/*  дÊý¾ÝWrite Data  */
void OLED_Write_Data(uint8 dat)
{uint8 i;OLED_DC_Set();OLED_CS_Clr();for (i = 0; i < 8; i++){OLED_SCLK_Clr();if (dat & 0x80) //ÅжÏÊý¾Ý×î¸ßλÊÇ1»¹ÊÇ0{OLED_SDIN_Set();}elseOLED_SDIN_Clr();OLED_SCLK_Set();dat <<= 1;}OLED_CS_Set();//    OLED_DC_Set();
}

6、全局变量统一在前面加g 或者加_ ,比如 _flag.

7、绘制一个像素点

/*  绘制一个像素至缓存Draw one pixel to buffer    */
void OLED_DrawPixel(uint8 x, uint8 y)
{uint8 mask;uint8 *pBuf;if (_x > WIDTH - 1){_x = 0;_y += 1;}if (_y > HEIGHT - 1){_y = 0;}pBuf = &_buf[(y >> 3) * WIDTH + x];mask = 1 << (y & 7);if (_OLED_Reverse){*pBuf++ &= ~mask;}else{*pBuf++ |= mask;}
}
   pBuf = &_buf[(y >> 3) * WIDTH + x];mask = 1 << (y & 7);

以上两句是写像素至缓存关键,即在_buf中储存相应的值,假设写的点为(4,8),则注意是从_x=0,_y=0开始写的,8是4列第9个点,写入的为一个字节的数据mask,y>>3是判断其所在的页,如果是第8个点(0-7是第一页),则是在第二页。_buf是一个线性数组,存第二页的数则应该是加上第一页的列数,即1*128+4即为要存的位置。

8、统一显示屏幕上所有内容

/*  将缓存内容显示到屏幕上Send buffer to display  */
void OLED_Display(void)
{uint8 i, j;uint8 *pBuf;pBuf = _buf;for (j = 0; j < PAGES; j++){for (i = 0; i < WIDTH; i++){OLED_Write_Data(*pBuf++);}}
}

9、旋转编码器的使用

EC11编码器资料参见如下的链接:

​​​​​​http://www.best-dz.com/Technical/info_itemid_1461.html#:~:text=ec11%E7%BC%96%E7%A0%81%E5%99%A8%E6%98%AF%E7%94%B1%E4%B8%80%E4%B8%AA%E4%B8%AD%E5%BF%83%E6%9C%89%E8%BD%B4%E7%9A%84%E5%85%89%E7%94%B5%E7%A0%81%E7%9B%98%EF%BC%8C%E5%85%B6%E4%B8%BB%E8%A6%81%E5%88%A9%E7%94%A8%E5%85%89%E7%94%B5%E8%BD%AC%E6%8D%A2%E5%8E%9F%E7%90%86%E8%BE%93%E5%87%BA%E4%B8%89%E7%BB%84%E6%96%B9%E6%B3%A2%E8%84%89%E5%86%B2A%E3%80%81B%E5%92%8CZ%E7%9B%B8%E3%80%82,%E4%B8%BA%E4%BA%86%E6%96%B9%E4%BE%BF%E5%9C%B0%E5%88%A4%E6%96%AD%E5%87%BA%E6%97%8B%E8%BD%AC%E6%96%B9%E5%90%91%EF%BC%8CA%E3%80%81B%E4%B8%A4%E7%BB%84%E8%84%89%E5%86%B2%E7%9B%B8%E4%BD%8D%E5%B7%AE%E5%BA%94%E4%B8%BA90o%E3%80%82%20%E8%80%8C%E4%B8%94ec11%E7%BC%96%E7%A0%81%E5%99%A8%E8%BD%B4%E8%BD%AC%E4%B8%80%E5%9C%88%E4%BC%9A%E8%BE%93%E5%87%BA%E5%9B%BA%E5%AE%9A%E7%9A%84%E8%84%89%E5%86%B2%EF%BC%8C%E5%9B%A0%E6%AD%A4%E7%BC%96%E7%A0%81%E5%99%A8%E5%85%89%E6%A0%85%E7%9A%84%E7%BA%BF%E6%95%B0%E5%86%B3%E5%AE%9A%E4%BA%86%E8%84%89%E5%86%B2%E6%95%B0%E3%80%82

P3.3为编码器按键信号,即普通按键一样操作;P3.2和P3.4为编码器脉冲信号,

P3.3链接到外部中断1,

P3.2连接外部中断0,

编码器p3.4 连接普通IO口。

void Scan_EC11(void)可以判断方向,但其要在INT0中断中使用才可以,因为其只是判断p3.2和p3.4是否相等,单独使用不可判断方向,当在INT0中使用时,INT0中断说明P3.2脚脉冲变化,该处中断设置为上升沿和下降沿均触发。根据波形图,设A-C之间为p3.2,在第一个下降沿触发了中断,在中断中,当p3.2和p3.4(B-C)状态相同(都为低电平),此时可以判断为正传,当状态不同时判断为反转。

旋转编码器还有一个开关信号,指示按下和弹起两个状态。于是可以组合出正传、反转、按下、弹起、按下正传、按下反转、等多种组合方式。

图源于:旋转编码开关 EC11 的工作原理_lovelijiapu的博客-CSDN博客

sbit EC11_KEY = P3 ^ 3; //编码器按键连接外部中断1 connect to External Interrupt 1
sbit EC11_A = P3 ^ 2;   //编码器A脉冲连接外部中断0 connect to External Interrupt 0
sbit EC11_B = P3 ^ 4;   //编码器B脉冲连接普通IO口 connect to GPIOvoid Scan_EC11(void)
{/* 延时去抖动Delay to remove jitter */Delay500us();/* 正转Clockwise */if (EC11_A != EC11_B){Change_Val(1);}/* 反转Anticlockwise */else if (EC11_A == EC11_B){Change_Val(0);}
}/* 编码器旋转中断Interrput for Encoder Rotated */
void INT0_interrupt(void) interrupt INT_0
{Delay500us();/* 编码器是否被按下Whether the Encoder is pressed */if (!EC11_KEY)EC11PressAndRotate = 1;elseEC11PressAndRotate = 0;Scan_EC11();ADCInterrupt = 1;DisplayUpdate = 1;IE1 = 0; //清零外部中断1标志位IE0 = 0; //清零外部中断0标志位
}/* 编码器点击中断Interrput for Encoder Pressed */
void INT1_interrupt(void) interrupt INT_1
{Delay50ms();if (!EC11_KEY){EC11PressAndRotate = 0;/*  长按编码器按键 - 切换主界面和设置界面Long presse Encoder - Switch main interface and settings interface */if (Delay800ms_Long_Press()){InSettings = ~InSettings;/*  进入设置界面Enter Settings  */if (InSettings){DisplayUpdate = 1;UpdateVbat = 1;TF0 = 0; //清零定时器0溢出标志TR0 = 1; //定时器0开始计时,开始电池电压信息更新计时IE0 = 0; //清零外部中断0中断标志EX0 = 1; //开启外部中断0(编码器旋转)}/*  回到主界面Retrurn to main interface   */else{TR0 = 0; //清零定时器0溢出标志TF0 = 0; //定时器0停止计时,停止电池电压信息更新计时WaveFreq = 0;TriFail = 0;VMax = 0;VMin = 0;DisplayUpdate = 1;WaveUpdate = 1;ClearWave = 0;}ADCInterrupt = 1;}/*  按住编码器同时旋转Rotate Encoder while pressing  */else if (EC11PressAndRotate){/* 由编码器旋转中断执行操作Operations Performed by Interrupt of Encoder Rotation */}/* 双击编码器按键 - 在主界面,滚动波形和选项模式之间切换Double click Encoder - Switch between Waveform Scroll Mode and Parameter Mode in Main Interface */else if (Delay300ms_Double_Click()){/* 主界面Main Interface*/if (!InSettings){WaveScroll = ~WaveScroll;OptionChanged = 1;ADCInterrupt = 1;DisplayUpdate = 1;ClearWave = 0;}}/*  单击编码器按键 - 在主界面,切换Stop/Run状态Single click Encoder - Switch Run/Stop in main interface    */else if (!InSettings){EX0 = 0;ADCRunning = ~ADCRunning;if (ADCRunning){WaveUpdate = 1;ClearWave = 1;}else{DisplayUpdate = 1;WaveUpdate = 1;}ADCInterrupt = 1;IE0 = 0;IE1 = 0;}}IE1 = 0;
}

 if (Delay800ms_Long_Press())  编码器长按,直接在if()中调用有返回值的函数,函数中如果编码器弹起或者旋转则返回,如果800ms内没变化则返回1。

bit Delay800ms_Long_Press() //@27.000MHz
{unsigned char i, j, k;_nop_();_nop_();i = 110;j = 148;k = 166;do{do{/* 编码器松开或转动Encoder released or rotated */if (EC11_KEY || EC11PressAndRotate)return 0;while (--k);} while (--j);} while (--i);return 1;
}

老刘示波器项目开发经验学习相关推荐

  1. 老刘说NLP:焦虑被大肆贩卖下的自然语言处理学习思考

    一.话题的由来 近期,有不少朋友来信,来询问如何看待自然语言处理这个方向,表示对当前的状态很不满,希望能够尽快地找到一个合适的方向.快速的学习方式,提升自己的自然语言处理能力,从而找到一个算法岗位的面 ...

  2. FPGA项目开发:基于JESD204B的LMK04821芯片项目开发经验分享

    大侠好,阿Q来也,今天头一次和各位见面,请各位大侠多多关照.今天给各位大侠带来一篇项目开发经验分享"基于JESD204B的LMK04821芯片项目开发",这是本人实打实的项目开发经 ...

  3. 一个40岁老程序员的前端学习之路|2021 年中总结

    40岁的老程序员感言 时光给我留下了什么? 不知不觉间虚度了40年光阴,看着父母逐渐的苍老和孩子逐渐长大,看着自己发福的身材,已知道自己在这个陌生的城市里已经扎根,估计是很难再去哪里了.回首故里似乎和 ...

  4. Android 开源项目及其学习

    Android 系统研究:http://blog.csdn.net/luoshengyang/article/details/8923485 Android 腾讯技术人员博客 http://hukai ...

  5. 大会直击|微软亚洲研究院刘铁岩:深度学习成功的秘密

    大会直击|微软亚洲研究院刘铁岩:深度学习成功的秘密 本文作者:宗仁 2016-09-09 21:46 导语:今天深度学习成功的主要因素:超大规模训练数据.复杂的深层模型.分布式并行训练,也正是影响其进 ...

  6. python解题教学设计的理解_面向计算思维培养的初中 Python 项目式学习教学设计流程构建...

    2006 年, 美国卡内基梅隆大学的周以真教授提出了计算思维的概念.计算思维是利用计算机科学的基本理念解决问题.设计系统和理解人类行为的一种方法,并指出计算思维的本质是抽象(Abstraction)和 ...

  7. 报名老刘的LinuxProbe,获取《Linux就该这么学》

    报名老刘的LinuxProbe 正文内容: 本书是由全国多名红帽架构师(RHCA)基于最新Linux系统共同编写的高质量Linux技术自学教程,极其适合用于Linux技术入门教程或讲课辅助教材,目前是 ...

  8. 基于STM32的简易示波器项目(含代码)——HAL库

            前言:本文基于STM32的简易示波器项目,示波器作为嵌入式开发中必不可少的器件,其使用方式和工作原理是必须被掌握的.巧妙利用STM32可以实现媲美度非常高的示波器,本文中的简易示波器主 ...

  9. 翻出来的老物件,11年学习易语言之后写的一个游戏策划脚本辅助工具

    翻出来的老物件,11年学习易语言之后写的一个游戏策划脚本辅助工具,某年因为某恶心的项目回乡之后,学了下E语言,学完之后手有点痒痒,于是乎自己想写点东西,因为本身做了很长时间游戏,所以想做个游戏相关的, ...

最新文章

  1. Python:变量与字符串
  2. 白话Elasticsearch68-ES生产集群部署重要的操作系统设置
  3. php检查运算是否错误,用PHP中的@运算符抑制错误
  4. #define中 #与##的神奇用法
  5. UVA - 10817 Headmaster's Headache
  6. tomcat ---- 常用服务器
  7. 【POJ】【3164】Commond Network
  8. bootstrap bootbox 属性及用法
  9. 挑战性价比,刷新你对千元级投影仪的认知,这份详细评测送给你
  10. 拉钩教育高薪训练营学习笔记——分布式理论与分布式架构设计理论
  11. JDE910笔记2--OMW项目建立及简单使用
  12. C 语 言制定了一套 ANSI 标准
  13. 计算机按键变成音符怎么弄,作曲大师怎么设置键盘输入 音符快速输入方法
  14. android 支付sdk流程,支付SDK
  15. nvcc fatal : Unsupported gpu architecture ‘compute_86‘
  16. Python读取Excel表格效率对比(openpyxl、xrld、csv)
  17. 单片机c语言波特率检测,基于MSP430系列微控制器串口通信时的波特率自动检测的实现...
  18. DASAN(V5824G)大山 OLT HGU (4GE+2VOIP)配置指导
  19. eml html显示工具,电脑打开eml文件的三种方法【图文教程】
  20. 东南大学计算机系和南大计算机系,东南大学:中国“985、211、双一流”大学!却很少人知道...

热门文章

  1. 与小我11岁的人一次PK
  2. Spring 的依赖注入
  3. mac os 10.10以上的开启端口转发-解决mac默认不开启1024以下端口权限问题
  4. 关于WCDB Swift 的一些简易使用
  5. 股价下跌由少数人决定
  6. Oracle-Alert log解读
  7. CISA证书为什么是IT行业薪酬最高之一
  8. 单片机串口中断控制流水灯c语言,基于单片机AT89C51控制的中断控制流水灯_课程设计报告...
  9. 多种方式进行数据库的批量删除(删除用户信息为例)
  10. 江西科技版四年级上册计算机教案,江西版2017四年级上册美术教学计划