找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3289|回复: 3
打印 上一主题 下一主题
收起左侧

Myos环境STM8开发持续更新帖

[复制链接]
跳转到指定楼层
楼主
ID:229155 发表于 2018-1-26 22:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    一直以来都想为Myos操作系统写一个开发者的入门帖,然而因为各种各样的原因,拖延到现在才开始编写。
    在这之前也尝试过很多种其他的方式,比如编写使用手册、编写例程、直播开发过程等等,后来都发现效果不好,还是有很多想要使用Myos的朋友无法真正熟练的使用。

    在这之前我曾经还想录制一个类似于现在某一个宝上销售的开发板的新手入门视频,还没动手呢,自己都觉得肯定没什么效果,琢磨来琢磨去决定发一个持续更新的帖子,尽量的坚持快速更新,讲解STM8、编程技巧、经验规范以及操作系统提供的功能等等。
    然而写帖子或者博客总得有一个话题,总不能我想到什么就给大家写什么,那样太乱了,也没有太多的营养。所以我决定走一个和现在卖开发板不同的路线,不再把各种例程分开写,而是按照实际的项目流程来,做一个相对于STM8来说非常复杂的项目,以此来给大家展示STM8和Myos操作系统。想了很久不知道到底做什么,然而就在上几天调试电路板,再想起以前调试电路板的经历,我决定写一个多功能的示波器,没错!就是用STM8写一个示波器!
    由于本帖是持续更新帖,所以在本段我会做一些说明:
      1.本帖中的软件环境是IAR For STM8,下位机的操作系统是Myos操作系统。
      2.本帖中的硬件环境是STM8S007C8、12864点阵屏、4M字节Flash以及矩阵按键等等常备的小玩意。
      3.本帖是持续更新帖,大家尽可能的私信我,给我发小纸条免得中途插楼太多影响大家阅读体验。
      4.本帖中所用到的硬件原理图和Myos操作系统环境我会以附件的方式上传到帖子上,大家都可以自由下载。
    以下均为技术干货帖。

Myos_Private_2_4_9.7z

2.53 MB, 下载次数: 26, 下载积分: 黑币 -5

开发板电路.pdf

83.33 KB, 下载次数: 15, 下载积分: 黑币 -5

STM8S系列参考手册.pdf

4.6 MB, 下载次数: 16, 下载积分: 黑币 -5

评分

参与人数 1黑币 +100 收起 理由
admin + 100 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:229155 发表于 2018-1-26 22:56 | 只看该作者
    既然是新手帖,写给新手们的入门帖,那自然要从最简单最基础的做起。
    学软件开发的入门实验可能是“hello world”也可能是“hello c”可能大家发挥想象,不一定是一样的,但是学单片机一定都是一样的,大家拿到单片机的第一个入门实验一定是:流水灯!
    话不多说,先截图上代码(贴在帖子中太小了,我弄到附件里面去了,大家将就看,嫌弃小的移步去附件),然后再讲解。
   

    首先,需要熟悉一下Myos的系统环境,左侧为系统的文件目录,具体如下:
   
    最前面的带Application前缀的应用程序文件夹,带device的是STM8的驱动文件夹,带Myos前缀的是系统核心文件夹,而Myos系统的主函数虽然也是从main函数开始运行,但是由于运行了Myos操作系统,所以不再使用main函数作为入口函数,而是以osdemo.c文件中的OS_ApplicationMainThread函数作为入口函数,翻译过来即为“应用程序主线程”。长这样:


    然后我们的代码写在这个函数内,由于这个函数是一个独立的线程,所以在函数的最后一定要记得添加OS_ThreadExit函数来执行线程销毁工作,否则函数退出时则会返回到一个未知的状态,也就是程序跑飞,但是需要注意的是只有在线程需要退出的时候才能调用这个函数,在任意一个用户线程中,只要调用了OS_ThreadExit函数则必然会导致当前的线程被销毁。
    OK,开始讲解代码:
    首先,我们定义一个regist变量来保存一下流水灯的状态,这个和51的流水灯实现还是略有区别的,需要注意的是STM8、Cortex M系列的微控制器并不支持对IO口的位操作,每次操作至少是以字节(8位)访问方式进行访问。
    接下来如下三行代码:
   
    我所使用的开发板上的四个LED灯是连接在PC1-PC4上的,所以需要设置一下PC口,首先看DDR寄存器,DDR寄存器是控制IO的数据方向的,输入还是输出由这个寄存器控制。而CR1在输出模式下是控制IO的输出类型,开漏(无法输出高电平)输出还是推挽输出。CR2则是输出模式下的IO翻转速度,置高为10MHZ。
    具体的寄存器说明可以参考上传的STM8S参考手册GPIO章节。
   
    循环体代码如上,首先我们的流水灯是一个死循环,一直执行流水灯操作,对于regist的操作就是流水灯的发生过程,由于我只有4个LED,所以不进行8bit移位,而是进行4bit循环移位。
    ODR寄存器是IO口的输出状态控制寄存器,置一则端口高电平输出,否则低电平输出,由于我的LED是低有效(低电平点亮),所以需要对数据进行取反,然后将流水灯状态写入ODR寄存器同步到硬件IO使IO完成对应的状态设置。
    而OS_ThreadDelay函数则是操作系统提供的系统函数,它的功能是完成延时,函数的入参是延时的时间,单位为毫秒,示例代码中写的是1000,也就是1秒(1000ms),流水灯的状态每秒刷新一次。需要注意的是OS_ThreadDelay函数是一个系统函数,内部的实现方式复杂,它并不占用定时器资源也不是CPU计数进行延时,在本线程延时的同时其他的线程还是可以继续运行。
    最后在线程主函数的最后是线程退出函数 ,此函数需要再次说明,只有在一个线程执行完成需要退出的时候才调用这个函数来释放线程资源,不是说任意一个函数中都需要调用这个函数,仅适用于每个线程的主函数(入口函数)。另外在本阶段暂时还不涉及多线程编程,所以大家并不需要太过于注意这个函数,只是暂时有这么个概念即可,目前的阶段大家不需要在自己编写的函数中调用。
    题外话:有关于线程、多任务和进程还请大家自行百度,本帖中就不做说明了,百度说得还是比较客观和清楚的。

回复

使用道具 举报

板凳
ID:229155 发表于 2018-1-27 23:21 | 只看该作者
昨天写了一下STM8环境下GPIO的流水灯操作说明以及操作系统的OS_ThreadDelay延时函数,然而流水灯只是最基本的一个小实验,并没有太大的实用价值,所以今天的帖子是GPIO操作的升级版,也是操作系统环境下的"管理组件"的驱动开发示例帖,今天的帖子是示范一下系统环境下的矩阵键盘驱动编写以及在STM8环境下的实现。
在Myos操作系统环境下的按键驱动接口原型有三个,代码如下:
  1. /*********************************************************************系统按键管理驱动函数*********************************************************************/
  2. /*
  3. *函数名:MCU_ButtonIOInit( void )
  4. *入参:无
  5. *返回值:无
  6. *作用域:本地
  7. *线程访问:回调
  8. *函数作用:初始化系统硬件成为可使用的按键输入
  9. */
  10. void MCU_ButtonIOInit( void )
  11. {
  12. }

  13. /*
  14. *函数名:MCU_GetButtonvallower( void )
  15. *入参:无
  16. *返回值:按下的按键状态
  17. *作用域:本地
  18. *线程访问:回调
  19. *函数作用:获取当前键盘中被按下的按键低32位
  20. */
  21. unsigned int32 MCU_GetButtonvallower( void )
  22. {
  23.   return 0x00;
  24. }

  25. /*
  26. *函数名:MCU_GetButtonvalhigh( void )
  27. *入参:无
  28. *返回值:按下的按键状态
  29. *作用域:本地
  30. *线程访问:回调
  31. *函数作用:获取当前键盘中被按下的按键高32位
  32. */
  33. unsigned int32 MCU_GetButtonvalhigh( void )
  34. {
  35.   return 0x00;
  36. }
复制代码
这三个驱动接口原型函数位于Myos_driver文件夹下的myosmanagedriver.c文件中,系统会在组件初始化阶段调用
MCU_ButtonIOInit函数来执行按键的输入输出口属性初始化工作,而在需要进行按键检测的时候通过调用MCU_GetButtonvallower和MCU_GetButtonvalhigh函数来获取最大64个按键的状态,并在系统内部进行处理,对按键进行单击、长按检测,并提供一系列的接口来使能或禁能按键的连续输出,具体的功能会在后续的帖子中一一说明。
我所使用的开发板上有一个2x3的矩阵键盘,共计6个按键,一般情况下入门单片机的时候大家接触的按键一般都是独立按键,也就是每个IO接一个按键,通过IO的状态来判定按键的按下或抬起状态,而在实际的项目中大多使用的是矩阵键盘。
矩阵键盘的原理实际上是分而治之,举个例子,大家上小学的时候举手,一个教室有很多行有很多列的学生,有的学生举手而有的学生不一定举手,而老师看的时候也不是同时看的,一般都是先看第一行,然后再看第二行、第三行,以此类推。矩阵键盘也是一样的原理,一行按键一行按键的检测。
话不多说,根据我手里开发板的原理进行驱动的编写,上传的文件中所有的文件均为只读文件,请大家找到对应的文件路径然后解除只读属性后进行修改,编写后的代码如下:
  1. /*********************************************************************系统按键管理驱动函数*********************************************************************/
  2. /*
  3. *函数名:MCU_ButtonIOInit( void )
  4. *入参:无
  5. *返回值:无
  6. *作用域:本地
  7. *线程访问:回调
  8. *函数作用:初始化系统硬件成为可使用的按键输入
  9. */
  10. void MCU_ButtonIOInit( void )
  11. {
  12.   GPIOD->DDR &= ~0x1C;                                                          //设置PD2-PD4为输入
  13.   GPIOD->CR1 |=  0x1C;                                                          //设置PD2-PD4为上拉
  14.   GPIOD->CR2 &= ~0x1C;                                                          //设置PD2-PD4不中断

  15.   GPIOA->DDR |= 0x06;                                                           //设置PA1-PA2为输出
  16.   GPIOA->CR1 &= ~0x06;                                                          //设置PA1-PA2为开漏
  17.   GPIOA->CR2 |= 0x06;                                                           //设置PA1-PA2为10MHZ
  18. }

  19. /*
  20. *函数名:MCU_GetButtonvallower( void )
  21. *入参:无
  22. *返回值:按下的按键状态
  23. *作用域:本地
  24. *线程访问:回调
  25. *函数作用:获取当前键盘中被按下的按键低32位
  26. */
  27. unsigned int32 MCU_GetButtonvallower( void )
  28. {
  29.   unsigned dshort16 regist;                                                      //寄存变量

  30.   GPIOA->ODR |= 0x06;                                                           //设置PA1-PA2为高电平
  31.   GPIOA->ODR &= ~0x04;                                                          //设置PA2位低电平,准备扫描第二行

  32.   OS_Delay(0x02);                                                               //等待IO稳定
  33.   regist = GPIOD->IDR;                                                          //获取第二行的状态
  34.   GPIOA->ODR |= 0x06;                                                           //设置PA1-PA2为高电平
  35.   GPIOA->ODR &= ~0x02;                                                          //设置PA1位低电平,准备扫描第一行

  36.   regist >>= 0x02;                                                              //进行按键处理同时等待IO稳定
  37.   regist <<= 0x03;                                                              //进行按键处理同时等待IO稳定
  38.   regist |= 0xFFC0;                                                             //进行按键处理同时等待IO稳定
  39.   regist |= ((GPIOD->IDR) >> 0x02);                                             //获取第一行的状态
  40.   regist = ~regist;                                                             //低电平有效转高位有效

  41.   return regist;                                                                //返回按键状态
  42. }

  43. /*
  44. *函数名:MCU_GetButtonvalhigh( void )
  45. *入参:无
  46. *返回值:按下的按键状态
  47. *作用域:本地
  48. *线程访问:回调
  49. *函数作用:获取当前键盘中被按下的按键高32位
  50. */
  51. unsigned int32 MCU_GetButtonvalhigh( void )
  52. {
  53.   return 0x00;
  54. }
复制代码
MCU_ButtonIOInit函数中对状态线PD2-PD4初始化为上拉输入,且不开启中断功能,那么这三个IO就相当于是一个高阻输入的IO再加一个上拉电阻,用来捕获按键的按下状态,而对扫描线PA1-PA2初始化为开漏输出,之所以设置为开漏输出是为了保证没有高电平输出,高电平由输入口的上拉电阻提供而不是由单片机的推挽输出提供,因为如果按键有时候会多个按键同时按下,一但PA1和PA2直接导通则会烧毁IO口,开漏输出由于没有高电平(扇出电流)输出所以不会导致IO的烧毁。另外我的板子上只有6个按键,所以没有必要使用高32位的驱动函数,只需要使用低32位的驱动函数来捕获按键状态既可。
MCU_GetButtonvallower函数里包含了矩阵按键的扫描方法,首先将置低PA2扫描第二行,因为我们采用的是左移的方式来处理,先扫描的按键值会更大,第一次扫描需要进行一些延时来等待IO状态稳定,OS_Delay这个函数也是一个系统函数,但是这个函数只是粗略延时,延时时长为:(参数*3)个时钟周期。而在第二次扫描的时候就可以进行regist变量的处理来模拟延时,同时也可以先进行一部分的处理工作,提高驱动的效率。当驱动写完后,则按键的键值编码如下:第一行(PA1)的第一个(PD2)为1、第二个(PD3)为2、第三个(PD3)为3;第二行第一个
(PD2)为4、第二个(PD3)为5、第三个(PD3)为6。
当需要进行按键检测的时候调用函数OS_GetKey或OS_GetChar即可获取到当前的按键状态,该函数的函数原型为:

  1. /*
  2. *函数名:OS_GetKey( void )
  3. *入参:无
  4. *返回值:当前按下的键值
  5. *作用域:本地
  6. *线程访问:安全
  7. *函数作用:获取当前键盘的键值,该函数不会阻塞线程,如没有按键按下则返回0,如为长按则最高位为1
  8. */
  9. unsigned char8 OS_GetKey( void );

  10. /*
  11. *函数名:OS_GetChar( void )
  12. *入参:无
  13. *返回值:获取当前按下的按键
  14. *作用域:本地
  15. *线程访问:安全
  16. *函数作用:获取当前的按键情况,该函数会阻塞线程,如果是长按则返回值的最高位为1
  17. */
  18. unsigned char8 OS_GetChar( void );
复制代码
上述两个函数均可获取按键的按键值,不同之处在于OS_GetKey不会阻塞当前的线程,如果没有按键按下则返回0,而
OS_GetChar会阻塞线程,如果没有按键按下则一直在本函数中等待,直到按键按下为止,而如果发生了长按则两个函数返回值的最高位(位7)均为1,低7位则是键值,键值对应关系为1~32为MCU_GetButtonvallower驱动函数返回值的0~31位,而33~64为MCU_GetButtonvalhigh驱动函数返回值的0~31位。
我在例程中使用的函数为
OS_GetKey来获取按键值,并且根据按键的值改变流水灯的移动速度,代码如下:
  1. #include "myos.h"
  2. #include "osdemo.h"



  3. /*
  4. *函数名:OS_ApplicationMainThread(void *arg)
  5. *入参:
  6.   arg:线程运行参数
  7. *返回值:无
  8. *作用域:本地
  9. *线程访问:安全
  10. *函数作用:应用程序主线程
  11. */
  12. void OS_ApplicationMainThread(void *arg)
  13. {
  14.   unsigned char8 key = 0x00;                                                    //按键寄存
  15.   unsigned char8 regist = 0x00;                                                 //寄存变量
  16.   unsigned short16 delay = 1000;                                                //延时寄存

  17.   GPIOC->DDR = 0x1E;                                                            //设置PC1-PC4为输出模式
  18.   GPIOC->CR1 = 0x1E;                                                            //设置PC1-PC4为推挽输出
  19.   GPIOC->CR2 = 0x1E;                                                            //设置PC1-PC4位10MHZ输出

  20.   while(true){
  21.     regist &= 0x0F;                                                             //只取4位有效位
  22.     regist = (regist == 0x00) ? 0x01 : (regist << 0x01);                        //流水灯移动及越界判定

  23.     GPIOC->ODR = (~regist << 0x01);                                             //LED灯点亮赋值

  24.     key = OS_GetKey();                                                          //获取键值
  25.     if(key > 0x00){                                                             //有按键按下
  26.       delay = key & 0x7F;                                                       //去除长按标识
  27.       delay *= 200;                                                             //计算延时时间
  28.     }

  29.     OS_ThreadDelay(delay);                                                      //系统提供的延时函数
  30.   }

  31.   OS_ThreadExit();                                                              //线程结束退出
  32. }
复制代码
OK,今天的帖子到此为止,下一个帖子的内容是SPI(串行外设接口)的科普帖。


按键驱动接口.jpg (56.68 KB, 下载次数: 117)

按键驱动接口

按键驱动接口
回复

使用道具 举报

地板
ID:229155 发表于 2022-9-29 19:25 | 只看该作者
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表