lvgl 学习笔记

 

LVGL使用笔记

LVGL使用笔记

位置

设置对象的位置

  1. 创建图形对象,其坐标在(0, 0)处

     lv_obj_t *obj = lv_obj_create(lv_scr_act())
    
  2. 将对象的坐标设置为(-50, 50)
     lv_obj_set_pos(obj, -50, 50);
    
  3. 对齐屏幕对象的某个坐标
  lv_obj_set_align(obj, LV_ALIGN_...);
  1. 对齐屏幕对象的某个区域再偏移
  lv_obj_align(obj, LV_ALIGN_..., x, y);
  1. 对齐任意对象(没有父子关系)
  lv_obj_t *obj = lv_obj_create(lv_scr_act());
  lv_obj_t *label = lv_label_create(lv_scr_act());
  lv_label_set_text(label, "Hello, LVGL!");
  //lv_obj_align_to(obj_align, obj_referece, LV_ALIGN_..., x, y);
  lv_obj_align_to(label, obj, LV_ALIGN_CENTER, 0, 0);

align

获取对象的位置

lv_obj_get_x(obj);
lv_obj_get_y(obj);

盒子模型(border-box)

设置盒子大小

lv_obj_t *obj = lv_obj_create(lv_scr_act());
lv_obj_set_size(obj, 300, 300);
printf("w: %d\n", lv_obj_get_width(obj));
printf("h: %d\n", lv_obj_get_height(obj));

屏幕是大盒子,中间的控件都是小盒子

box

  • outline:按tab键时的高亮外框

  • 修改厚度

    lv_obj_t *obj = lv_obj_create(lv_scr_act());
    lv_obj_align(obj, LV_ALIGN_CENTER, 0, 0);
    lv_obj_set_style_border_width(obj, 10, 0);
    

    box1

  • 修改outline

    lv_obj_t *obj = lv_obj_create(lv_scr_act());
    lv_obj_align(obj, LV_ALIGN_CENTER, 0, 0);
    lv_obj_set_style_border_width(obj, 10, 0);
    lv_obj_set_style_outline_width(obj, 10, 0);
    

    box2

    • outline 不在盒子里面

      box3

    • outline不占盒子空间

      box4

基础对象的样式style

  • 样式
    • 用名称保存下来一组修饰参数。比如鼠标移到到图标上,图标变色这就是改变了图标的样式
    • 用于设置对象的外观。
    • 样式是一个 lv_style_t 变量,它可以保存边框宽度、文本颜色等属性。
    • 将样式(变量)分配给对象就可以改变其外观。在赋值过程中,可以指定目标部分目标状态
    • 一个样式可以给多个对象使用(正常样式)。
    • 样式可以级联,也就是可以将多个样式分配给一个对象。所以,我们不用将所有属性都在一个样式中指定,可以通过多个样式组合的形式指定。 LVGL 会优先使用我们定义的样式,如果没有就会使用默认值。
    • 后来添加的样式具有更高的优先级。也就是说如果在两种样式中指定了同一个属性,则将使用最后添加的样式。
    • 如果对象中未指定某些属性(例如文本颜色),就会从父级继承。
    • 上面说的是 “正常” 样式,对象还有本地样式,它比 “正常” 样式具有更高的优先级。
    • 可以定义有过渡效果的样式。
    • 默认有一个样式主题,我们也可以自己定义样式主题,作为默认的样式主题使用
    • 样式存储在 lv_style_t 变量中,样式不能是局部变量,否则函数结束时会被销毁。

初始化

static lv_style_t style_obj;
lv_style_init(&style_obj);

设置样式属性

初始化好一个样式之后,设置它的属性:

lv_style_set_<property_name>(&style, <value>);

比如:

lv_style_set_bg_color(&style_obj, lv_color_hex(0x000000));   // 设置背景色
lv_style_set_bg_opa(&style_obj, LV_OPA_50);	                // 设置背景透明度
lv_style_set_....

添加(应用)样式到对象

初始化->设置->添加样式

lv_obj_add_style(obj, &style, <selector>)
  • <selector> 是应添加样式的部分和状态的 OR-ed 值
lv_obj_add_style(obj, &style_obj, 0);   		          // 默认(常用)
lv_obj_add_style(obj, &style_obj, LV_STATE_PRESSED);  // 在对象被按下时应用样式

获取样式属性

lv_obj_get_style_<property_name>(obj, <part>);

lv_color_t color = lv_obj_get_style_bg_color(obj, LV_PART_MAIN);

删除样式

  • 删除所有样式

    lv_obj_remove_style_all(obj);
    
  • 删除特定样式

    lv_obj_remove_style(obj, &style_obj, selector);
    
    • 只有当 selector 与 lv_obj_add_style 中使用的 selector 匹配时,此函数才会删除 style
    • 如果 style 是空,那么会根据给出的 selector 检查并删除所有匹配的样式
    • 如果 selector 是 LV_STATE_ANY 或 LV_PART_ANY 就会删除具有任何状态或部分的样式
    • 下面这个效果和lv_obj_remove_style_all 的效果是一样的

        lv_obj_remove_style(obj, NULL, LV_STATE_ANY | LV_PART_ANY );
      

查看样式属性

  • 文档位置:
  • 代码位置
    • 普通样式:lvgl/src/misc/lv_style_gen.h
    • 本地样式:lvgl/src/core/lv_obj_style_gen.h

背景部分的属性

  • 背景(Background)
  • 边界(Border)
  • 轮廓(Outline)
  • 阴影(Shadow)
  • 填充(Padding)
  • 宽度和高度变换
  • X和Y变换

样式的状态和部分

状态

对象可以处于以下状态的组合:

  • LV_STATE_DEFAULT (0x0000) 正常,释放状态
  • LV_STATE_CHECKED (0x0001) 切换或检查状态
  • LV_STATE_FOCUSED (0x0002) 通过键盘或编码器聚焦或通过触摸板/鼠标点击
  • LV_STATE_FOCUS_KEY (0x0004) 通过键盘或编码器聚焦,但不通过触摸板/鼠标聚焦
  • LV_STATE_EDITED (0x0008) 由编码器编辑
  • LV_STATE_HOVERED (0x0010) 鼠标悬停(现在不支持)
  • LV_STATE_PRESSED (0x0020) 被按下
  • LV_STATE_SCROLLED (0x0040) 正在滚动
  • LV_STATE_DISABLED (0x0080) 禁用状态
  • LV_STATE_USER_1 (0x1000) 自定义状态
  • LV_STATE_USER_2 (0x2000) 自定义状态
  • LV_STATE_USER_3 (0x4000) 自定义状态
  • LV_STATE_USER_4 (0x8000) 自定义状态

部分(Part)

对象可以有 部分(parts) ,它们也可以有自己的样式。LVGL 中存在以下预定义部分:

  • LV_PART_MAIN 类似矩形的背景
  • LV_PART_SCROLLBAR 滚动条
  • LV_PART_INDICATOR 指标,例如用于滑块、条、开关或复选框的勾选框
  • LV_PART_KNOB 像手柄一样可以抓取调整值
  • LV_PART_SELECTED 表示当前选择的选项或部分
  • LV_PART_ITEMS 如果小部件具有多个相似元素(例如表格单元格)
  • LV_PART_TICKS 刻度上的刻度,例如对于图表或仪表
  • LV_PART_CURSOR 标记一个特定的地方,例如文本区域或图表的光标
  • LV_PART_CUSTOM_FIRST 可以从这里添加自定义部件。

例如一个 滑杆(Slider) 包含三个部分:

  • 背景
  • 指标
  • 旋钮

这意味着滑块的所有三个部分都可以有自己的样式

本地样式

  • 除了“普通”样式外,对象还可以存储本地样式(私有样式)
  • 本地样式与普通样式类似,但是它不能在其他对象之间共享
    • 如果使用本地样式,将自动分配局部样式,并在删除对象时释放
    • 本地样式对于向对象添加本地自定义很有用
  • 接口API

    lv_obj_set_style_<property_name>(obj, <value>, <selector>);
    
    lv_obj_set_style_bg_color(obj,  lv_color_hex(0xffffff), 0);   // 设置背景色
    lv_obj_set_style_bg_opa(obj, LV_OPA_50, 0);	  // 设置背景透明度
    
  • 删除本地样式的时候我们删除某一个样式

    lv_obj_remove_local_style_prop(obj, LV_STYLE_..., selector);
    

样式继承

  • 某些属性(通常与文本相关)可以从父对象的样式继承
  • 只在没有为对象设置样式属性的时候,才应用继承
    • 在这种情况下,如果这个属性是可继承的,那这个属性的值会在父类中检索,直到一个对象为该属性指定了一个值
    • 父类将使用自己的状态来确定该值。 因此,如果按下按钮,并且文本颜色来自此处,则将使用按下的文本颜色

过渡特效

默认情况下,当一个对象改变状态(例如它被按下)时,新状态的新属性会立即设置。但是,通过转换,可以在状态更改时播放动画。 例如,按下按钮时,其背景颜色可以在 300 毫秒内动画显示为按下的颜色

样式主题

  • 主题是风格的集合
    • 如果存在活动主题,LVGL将其应用于每个创建的部件(对象)

事件冒泡

  • 对象打开lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE)功能,它就可以把事件送给它的父类
  • lv_event_get_target(e)得到的是事件第一的作用的对象
  • lv_event_get_current_target(e)是事件当前最终的作用对象
  • 传入的user_data不一致时,obj可以绑定同一个事件回调多次,事件按添加的顺序调用

      lv_obj_add_event_cb(obj, event_cb, LV_EVENT_CLICKED, &num1);
      lv_obj_add_event_cb(obj, event_cb, LV_EVENT_CLICKED, &num2);
    

LVGL的使用过程

  • obj: PSSt + event
  • label: TCLS + event

  • 我们开始先拿到屏幕scr = lv_scr_act(),以后的所有图形都是放在这个屏幕上的
    • 除了屏幕,LVGL还有lv_layer_top()顶层(用来弹框)和lv_layer_sys()系统层(用来放鼠标)两层
  • 然后,在屏幕上创建一个对象obj = lv_obj_create(scr)
  • 有了对象,就设置对象的位置pos、大小size、样式style
    • 设置这个对象的位置
      • 用坐标定义位置:lv_obj_set_pos(obj, 100, 100)
      • 用对齐父对象定义位置:lv_obj_align(obj, LV_ALING_CENTER, 0, 0)
      • 或者对齐另一个对象来定义位置:lv_obj_align_to(obj, other_obj, LV_ALIGN_CENTER, 0, 0)
    • 设置它的大小size
      • lv_obj_set_size(obj, 100, 100)
    • 设置它的样式 style
      • 可以直接设置它的样式和交互,从外到内设置样式,样式还要确定生效的时机,因为有时需要选定之后再应用新的样式,增加交互感
        • 样式一般包括
          • 宽度 width
          • 颜色 color
          • 遮光度 opa
        • 设置它的轮廓,并立即生效:lv_obj_set_style_outline_width(obj, 10, 0)
        • 设置它的边框,并立即生效:lv_obj_set_style_border_width(obj, 10, 0)
      • 也可以先定义一个样式变量,它再加载这个样式变量
        • 先定义一个样式变量:lv_style_t style; lv_style_init(&style)
        • 然后依次增加样式:lv_style_set_bg_color(&style, lv_color_black();
        • 最后让对象加载并立即应用这个样式lv_obj_add_style(obj, &style, 0)
  • obj的位置和样式都设置好了,还可以让它能激发一个事件回调功能
    • 增加事件回调:lv_obj_add_event_cb(obj, event_cb, event_code, user_data)
      • event_code: LV_EVENT_ALL(所有事件),LV_EVENT_CLICKED(点击)
    • 再实现回调功能

      void event_cb(lv_event_t *e) {
          lv_obj_t *target = lv_event_get_target(e);
          lv_obj_set_style_bg_color(obj, lv_color_hex(0x00), 0);
      
          lv_event_code_t  code = lv_event_get_code(e);
          switch (code) {
              case LV_EVENT_CLICKED: ...; break;
              case LV_EVENT_PRESSING: ...; break;
              case LV_EVENT_PRESSED: ...; break;
              case LV_EVENT_LONG_PRESSED: ...; break;
              default: break;
          }
      
          lv_obj_t *label = lv_event_get_user_data(e);
      }
      
      • 还可以在回调中发事件发送给其他对象
        • lv_event_send(lv_obj_t * obj, event_code, void * param)
        • 这里的param要通过void * lv_event_get_param(lv_event_t * e)获取
  • 上面是一个普通的对象经过的设置:psst + event
  • 下面是特定的对象,比如标签label,滚动条scorllbar
  • label标签
    • 首先,在屏幕中生成一个标签:lv_obj_t *label = lv_label_create(scr)
      • 然后设置文本
        • 指定文本:lv_label_set_text(label, "hello world")
          • 格式化文本:lv_label_set_text_fmt(label, "%s.%d", "ab", 15)
    • 对很长的文本设置截取方式
      • lv_label_set_long_mode(label, LV_LABEL_LONG_SCROLL_CIRCULAR)
        • LV_LABEL_LONG_DOT: 长的用…代替
        • LV_LABEL_LONG_WRAP: 长的换行
        • LV_LABEL_LONG_CLIP:截断
        • LV_LABEL_LONG_SCROLL:滚动
    • 设置了txtlong,还可以设置文本颜色和生效时机
      • lv_label_set_style_text_color(label, lv_color_hex(0xabcd), 0)
      • lv_obj_add_style(label, &style, 0)
        • 给文本分段着色

          lv_label_set_recolor(label, true);
          lv_label_set_text(label, "#0000ff Re-color# #00ff00 world# #ff0000 of a# label");
          
      • 图标文本
        • 除了正常文字,还有icon文本
        • lv_label_set_text(lable, LV_SYMBOL_OK)
        • lv_label_set_text(lable, LV_SYMBOL_OK LV_SYMBOL_WIFI "apple")
      • 设置文本的艺术字体S
        • 声明自定义的字体:LV_FONT_DECLARE(my_font_array)
        • 设置文本的字体:
          • 直接设置:lv_obj_set_style_text_font(label, &my_font_array, 0)
          • 加载样式:lv_obj_add_style(label, &style, 0)
        • 设置文本的图标文字
          • uiw-icons中可以查看到每个图标文字对应的unicode编码
            • &#dddd;是10进制的unicode编码
            • &#xdddd;是16进制的unicode编码
          • uiw-icons字体下载下来后,在字体转换器中转换要使用的图标
          • unicode-utf8中把unicode转换成对应的utf8编码,
            • 比如第图标&#59906;的unicode编码是0000EA02
            • 选择unicode编码即可得到utf8编码为EEA882
            • 在C代码中写上lv_label_set_text(titile1, "\xee\xa8\x82");即可显示图标
      • 设置好了TCLS,还可以让它触发event_cb
        • 增加点击功能:lv_obj_add_flag(label, LV_OBJ_FLAG_CLICKABLE)
        • 关联event_cb:lv_obj_add_event_cb(label, event_cb, event_code, user_date)
  • 组group
    • 作用
      • 我们把要用键盘、按键控制的组件加到一个组中
      • 组中每次只有一个对象聚集
      • 聚集的对象会接收按键或编码器的动作
    • 默认组
      • 创建组:lv_group_t *g = lv_group_create()
      • 组设置为默认:lv_group_set_default(g)
      • 输入设备设置关联组:lv_indev_set_group(indev, g)
      • 所有对象创建时会自动放到默认组中

        这个默认组好像有问题,还是用自定义组吧

    • 自定义组
      • 创建组:lv_group_t *g = lv_group_create()
      • 给组加对象:
        • lv_group_add_obj(g, bnt1)
        • lv_group_add_obj(g, bnt2)
      • 输入设备设置关联组:lv_indev_set_group(indev, g)
      • 集聚时边框高亮

          lv_obj_set_style_border_color(l1, lv_color_black(), LV_STATE_FOCUSED);
          lv_obj_set_style_border_width(l1, 2, LV_STATE_FOCUSED);
        
        • LV_KEY_NEXT, LV_KEY_PREV用于导航键,我们在设置事件触发时和LV_KEY_LEFT, LV_KEY_RIGHT是不同的

          lv_obj_add_event_cb(btn, event_handler, LV_EVENT_KEY, NULL);
          
          • LV_KEY_NEXT, LV_KEY_PREV不会触发LV_EVENT_KEY事件
          • LV_KEY_LEFT, LV_KEY_RIGHT会触发LV_EVENT_KEY事件
      • 删除页面,创建新组
        • 注意要删除旧组,否则新组接收不到按键
          • lv_group_del(g)

LVGL 在CSM11620B上的移植

  • CSM11620B液晶屏采用的是
    • ST7571的驱动器
    • 它是4级灰度的液晶显示系统
    • 可以通过SPI,I2C或8bit平行显示数据
    • 显示数据RAM是 128 x 129 x 2bits
  • ST7571使用Segment(列)和Common(行)的术语
    • 128 segment x (128+1) common
    • 其中最后1行是icon行,用于显示图标,只能通过专门的指令控制

ST7571 液晶驱动芯片

ST7571是一个用于4级灰度图形点阵液晶显示系统的驱动器和控制器LSI。该芯片直接与微处理器连接,接受串行外设接口(SPI)、I C或8位并行显示数据,并存储在128 x 129 x 2位的片上显示数据RAM中。它在执行显示数据RAM的写入操作时不需要外部操作时钟,以尽量减少功耗。此外,由于它包含了驱动液晶所需的电源电路,因此可以用最少的元件制作显示系统。

系统框图

diagram

Pin脚描述

微处理器接口

名称 I/O 说明
RST I 复位;L:执行初始化
PS[2:0] I 选择接口模式:SPI 4-Line
CSB I 片选,L:有效
A0 I 寄存器选择,H:显示数据;L:控制指令
DB[7:0] I 3-Line/4-Line:DB7 - SID;DB6-SCLK;DB[0:5]:高阻态

4-Line SPI 模式

线号 名称 说明
1 CSB 片选信号(低有效)
2 SID 串行数据
3 SCLK 串行时钟
4 A0 H:数据;L:命令

4-Line 时序

timer

  • 当IC处于激活状态(CSB=”L”)时,串行数据(SID)和串行时钟(SCLK)输入被激活。
  • 当ST7571不工作时(CSB=”H”),内部8位移位寄存器和3位计数器被复位。
  • 显示数据/命令指示由寄存器选择引脚(A0)控制。
    • 当A0为高电平时,数据总线上传输的信号将是显示数据,
    • 当A0为低电平时将是指令。
    • 不支持读取功能。
  • SID上的串行数据在SCLK上的串行时钟th的上升沿被锁住。
    • 在8个串行时钟之后,串行数据将被处理为8位并行数据。
    • 在每个字节的DDRAM访问之后,DDRAM的列地址指针将自动增加一个。

数据传输

ST7571使用总线支架(holder)和内部数据总线,由MPU进行数据传输。当从MPU向片上RAM写入数据时,数据会自动从总线支架传输到RAM,如图10和图11所示。

fig

显示数据RAM (DDRAM)

显示数据RAM用于存储LCD的像素数据。它是129行128列的可寻址阵列。当页面和列地址被指定时,每个像素都可以被选择。129行被分为16页,每页8行,第17页为单行(仅DB0)。数据直接通过DB0到DB7写到每页的8行中。来自微处理器的DB0到DB7的显示数据对应于LCD的common lines。LCD控制器和MPU接口独立工作,数据可以在显示数据的同时写入RAM,不会导致LCD显示有闪烁。

image: 128 x 128 = 16(page) x 8(row) x 128(col)

icon: 1 x 128

对于 128x128 的图像,img[127][127] 分成 img[0:7][0:127]img[8:15][0:127]…共16个页

绘图时,是img[0:7][y] = DB[7:0] = 0b0010_0110

  • DB[0] = 0对应最左上角的像素点为白色
  • DB[1] = 1对应下一个像素点为黑色

image-20220711183535645

继续写DB[0:7]时,列col会自动加1,从而DB[7:0] = 0b01001001是绘制第2列的像素

image-20220711183810284

页面地址电路 Page Address Circuit

它包含了4位的页面地址寄存器,只通过 “设置页面 “指令来改变。页地址16是一个特殊的RAM区域,用于图标icon,并且只有显示数据DB0有效。页面地址的设置范围是0到15,第16页是图标页。

行地址电路 Line Address Circuit

该电路为DDRAM分配了一个与显示器第一行(COM0)相对应的行地址。因此,通过反复设置行地址,可以在不改变片上RAM内容的情况下实现屏幕滚动和页面切换。它包含了仅由初始显示行指令和7位计数器电路改变的7位行地址寄存器。在每个LCD帧的开始,寄存器的内容被复制到行计数器中,该计数器被CL信号增加,并产生行地址,用于将128位RAM数据传输到显示数据锁存电路。当通过设置图标控制寄存器启用图标时,图标的显示数据不会被滚动,因为MPU不能访问图标的行地址。

列地址电路

当发出设置列地址MSB/LSB指令时,7位(X[7:1])被设置,最低位(X0)被设置为 “0”。在每一个字节的数据访问(写数据)之后,内部的列地址(X[7:0])会自动增加1。顺序访问两次后,列地址(X[7:1])将指向下一个列地址。请参考图12。

分段控制电路

该电路通过显示ON/OFF、反向显示ON/OFF和整个显示ON/OFF指令控制显示数据,而不改变显示数据RAM中的数据。

display

列地址和分段输出之间的关系

复位

将RST设置为 “L “可以初始化内部功能。RST引脚与MPU的复位引脚相连,在操作前必须通过RST引脚进行初始化。请注意,硬件复位与软件复位不一样。当RST变成 “L “时,硬件复位程序将开始。当RESET指令被执行时,软件复位程序将开始

开机后,RAM数据是未定义的,显示状态为 “Display OFF”。建议在打开显示器之前,对整个DDRAM进行初始化(例如:填满所有的00h或者写一个显示模式)(也包括ICON RAM)。此外,在刚刚打开电源的时候,系统电源并不稳定。在系统电源稳定后,需要进行硬件复位以初始化内部寄存器。

指令说明

Set Mode

这条2字节的指令指定帧频率(FR[3:0])和增压效率(BE[1:0])。

内部助推器的效率可以通过BE[1:0]来配置。最佳的设置是3级。

Write Display Data

来自微处理器的显示数据的8位数据可以被写入由列地址和页地址指定的RAM位置。列地址会自动增加1,这样微处理器就可以连续向寻址的页面写入数据。在自动增加的过程中,在最后一列被写入后,列地址会被回退为0。

wd

7.2 DISPLAY DATA RAM (DDRAM)

The Display Data RAM stores pixel data for the LCD. It is 129-row by 128-column addressable array. Each pixel can be selected when the page and column addresses are specified. The 129 rows are divided into 16 pages of 8 lines and the 17 th page with a single line (DB0 only). Data is written to the 8 lines of each page directly through DB0 to DB7. The display data of DB0 to DB7 from the microprocessor correspond to the LCD common lines. The LCD controller and MPU interface operate independently, data can be written into RAM at the same time when data is being displayed without flicker on LCD.

显示数据RAM存储LCD的像素数据。它是129行128列可寻址数组。当指定页面和列地址时,可以选择每个像素。129行分为16页8行,第17页一行(仅DB0)。数据直接通过DB0到DB7写入每个页面的8行。来自微处理器的DB0到DB7的显示数据对应于LCD公共线。LCD控制器和MPU接口独立运行,当数据在LCD上显示时,可以同时将数据写入RAM,而不会闪烁。

9. 指令

9.1 Set Mode

此2字节指令指定帧频(FR[3:0])和升压效率(BE[1:0])

image-20220711161632269

帧频和升压效率:

image-20220711161922453

9.2 Write Display Data

8-bit data of Display Data from the microprocessor can be written to the RAM location specified by the column address and page address. The column address is increased by 1 automatically so that the microprocessor can continuously write data to the addressed page. During auto-increment, the column address wraps to 0 after the last column is written.

来自微处理器的显示数据的8位数据可以写入由列地址和页地址指定的RAM位置。列地址自动增加1,以便微处理器可以连续将数据写入寻址页。在自动递增期间,在写入最后一列后,列地址换行为0。

image-20220711162131008

9.1.3 Set Icon

This instruction makes Icon function enable or disable. After reset, the Icon function is disabled (ION=0). When ION=“1”, Icon display is enabled and the page address is set to “16” for updating icon data (it is impossible to set page address to “16” by Set Page Address instruction). Therefore, when writing data for icons, “Set Icon” instruction is necessary before writing icon data. It set the page address to “16” before writing icon data. When “ION” is “0”, Icon display function is not available.

此指令使图标功能启用或禁用。重置后,图标功能被禁用(ION=0)。当ION=“1”时,图标显示启用,页面地址设置为“16”以更新图标数据(不可能通过设置页面地址指令将页面地址设置为“16”)。因此,在为图标写入数据时,在写入图标数据之前需要“设置图标”指令。在写入图标数据之前,它将页面地址设置为“16”。当“ION”为“0”时,图标显示功能不可用。

image-20220711162447385

9.1.4 Set Page Address

This instruction sets the Page Address of display data RAM from the microprocessor into the page address register. Any RAM data bit can be accessed when its Page Address and column address are specified. Along with the column address, the Page Address defines the address of the display RAM to write display data. Changing the Page Address doesn’t affect the display status. Set Page Address instruction can not be used to set the page address to “16”. Use ICON control register ON/OFF instruction to set the page address to “16”.

该指令将显示数据RAM的页面地址从微处理器设置到页面地址寄存器中。当指定其页地址和列地址时,可以访问任何RAM数据位。页面地址与列地址一起定义了用于写入显示数据的显示RAM的地址。更改页面地址不会影响显示状态。设置页面地址指令不能用于将页面地址设置为“16”。使用图标控制寄存器开/关指令将页面地址设置为“16”。

image-20220711162644636

9.1.5 Set Column Address

These instructions set the specified column address of DDRAM into the internal Column Address register. The internal Column Address register points to the address of DDRAM for accessing display data. The Column Addresses register is automatically increased by 1 when the microprocessor accesses the display data in DDRAM.

这些指令将DDRAM的指定列地址设置到内部列地址寄存器中。内部列地址寄存器指向DDRAM的地址,用于访问显示数据。当微处理器访问DDRAM中的显示数据时,列地址寄存器自动增加1。

image-20220711162758407

9.1.6 Display ON / OFF

This instruction turns the display ON or OFF. It has priority over Entire Display ON/OFF and Reverse Display ON/OFF.

此指令打开或关闭显示器。它优先于整个显示打开/关闭和反转显示打开/关闭。

image-20220711162935402

9.1.7 Set Display Start Line

This 2-byte instruction sets the line address of DDRAM to determine the first display line. The display data of the selected line will be displayed at the top of row (COM0) on the LCD panel.

此2字节指令设置DDRAM的行地址,以确定第一个显示行。选定行的显示数据将显示在LCD面板上的行顶部(COM0)。

image-20220711163113609

9.1.8 Set COM0

This 2-byte instruction set the initial row (COM) of the LCD panel. By using this instruction, it is possible to realize the window moving without the change of display data.

此2字节指令设置LCD面板的初始行(COM)。通过使用该指令,可以在不改变显示数据的情况下实现窗口移动。

image-20220711163331019

9.1.9 Set Display Duty

This 2-byte instruction sets the display duty within the range of 1/(16+1) to 1/(128+1) to realize partial display.

该2字节指令将显示占空比设置在1/(16+1)到1/(128+1)的范围内,以实现部分显示。

image-20220711163442709

设置N线反转(建议全负荷12线反转,1/129负荷)

This 2-byte instruction sets the inverted line number within range of 3 to 33 to improve the display quality by controlling the phase of the internal Frame signal. The DC bias maybe occurred if the N-line is not set well. Be sure to confirm this factor after choosing a value of N.

该2字节指令将反转行号设置在3到33的范围内,以通过控制内部帧信号的相位来提高显示质量。如果N线设置不好,可能会出现直流偏置。在选择N值后,确保确认该系数。

image-20220711163732563

移植过程

  • 修改lvgl/lv_conf.h

      #define LV_COLOR_DEPTH 1 // 颜色深度只用单色
      #define LV_MEM_SIZE (12U * 1024U) // 减少内存
      #define LV_MEM_BUF_MAX_NUM 8    // 渲染用的缓存单元大小,对于单色8bit够用
      #define LV_DPI_DEF 89     // DPP 改小
      // 去除所有主题...
    
  • 修改lvgl/src/porting/lv_port_disp.c

    • 修改void lv_port_disp_init(void)函数,把example2/3注释掉
    • 实现disp_init()

        static void disp_init(void) { /*You code here*/
            lcd_new();
            initial_st7571();
            clear_screen();
        }
      
    • 实现disp_flush函数

        static void disp_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area,
                            lv_color_t *color_p) {
            if (disp_flush_enabled) {
                int32_t x, y;
                for (y = area->y1; y <= area->y2; y++) {
                    for (x = area->x1; x <= area->x2; x++) {
                        set_pixel(x, y, color_p->full);
                        color_p++;
                    }
                }
                fill_color(area->x1, area->y1, area->x2, area->y2);
            }
        }
      
        /* 因为ST7571是以8行为一个单元,填充一个单元后列自动加1的方式显示的
            128 x 128 就变成 16 x 128,即128行分成16页
        */
        void fill_color(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) {
            uint8_t p1 = y1 / 8;    // y1在哪页
            uint8_t p2 = y2 / 8;    // y2 在哪页
            for (uint8_t p = p1; p <= p2; p++) {
                set_page(p);
                set_column(x1);
                for (uint8_t x = x1; x <= x2; x++) {
                    lcd_snd_data(image[p][x]);
                    lcd_snd_data(image[p][x]);
                }
            }
        }
      
  • 修改lvgl/src/porting/lv_port_indev.c

    • 注册掉不用的输入设备
    • 实现keypad_init()

        static void keypad_init(void) { /*Your code comes here*/
            T_GPIO_OBJ *gpio = gpio_new(eGPIOE);
            // KEY_ESC
            gpio->set_input_mode(GPIO_PIN_9, gpio);
            // KEY_ENTER
            gpio->set_input_mode(GPIO_PIN_10, gpio);
            // KEY_DOWN
            gpio->set_input_mode(GPIO_PIN_11, gpio);
            // KEY_UP
            gpio->set_input_mode(GPIO_PIN_12, gpio);
        }
      
    • 实现keypad_read()

        static void keypad_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data) {
            static uint32_t last_key = 0;
      
            #if 0
            /*Get the current x and y coordinates*/
            mouse_get_xy(&data->point.x, &data->point.y);
            #endif
      
            /*Get whether the a key is pressed and save the pressed key*/
            uint32_t act_key = keypad_get_key();
            if (act_key != 0) {
                data->state = LV_INDEV_STATE_PR;
      
                /*Translate the keys to LVGL control characters according to your key
                * definitions*/
                switch (act_key) {
                    case 1: act_key = LV_KEY_NEXT; break;
                    case 2: act_key = LV_KEY_PREV; break;
                    case 3: act_key = LV_KEY_LEFT; break;
                    case 4: act_key = LV_KEY_RIGHT; break;
                    case 5: act_key = LV_KEY_ENTER; break;
                    case 6: act_key = LV_KEY_ESC; break;
                }
      
                last_key = act_key;
            } else {
                data->state = LV_INDEV_STATE_REL;
            }
            data->key = last_key;
        }
      
    • 实现keypad_get_key()实现

        static uint32_t keypad_get_key(void) {
            /*Your code comes here*/
            T_GPIO_OBJ *gpio = gpio_new(eGPIOE);
            if (NULL == gpio) {
                return 0;
            }
      
            uint32_t act_key = 0;
            switch (GET_BITS(gpio->input(gpio), 9, 12)) {
                case 0xe: act_key = 6; break; // KEY_ESC
                case 0xd: act_key = 5; break; // KEY_ENTER;
                case 0xb: act_key = 3; break; // KEY_DONW 
                case 0x7: act_key = 4; break; // KEY_UP
                default: break; 
            }
      
            return act_key;
        }
      
    • lvgl先调用keypad_get_key()得到当前按键,再通过keypad_read转换为LVGL内部的按键类型
  • 最后还要给LVGL提供一个时钟和事件处理任务,至此移植结束

      extern void lvgl_tick_entry(void *args) {
          while (1) {
              lv_tick_inc(LVGL_TICK);
              delay_1ms(LVGL_TICK);
          }
      }
    
      extern void lvgl_event_entry(void *args) {
          while (1) {
              lv_timer_handler();
              delay_1ms(LVGL_TICK);
          }
      }
    
      static void lvgl_task_init() {
          BaseType_t xReturn = pdPASS;
    
          xReturn = xTaskCreate(lvgl_event_entry, "lvglevent", 2048, NULL, 2, NULL);
          if (xReturn != pdPASS) {
              printerr("创建lvgl event任务失败\n");
          }
    
          xReturn = xTaskCreate(lvgl_tick_entry, "lvgltick", 512, NULL, 2, NULL);
          if (xReturn != pdPASS) {
              printerr("创建lvgl tick任务失败\n");
          }
      }
    

DS18S20 温度传感器

  • 数据传输时序
    • 初始化
    • ROM指令
    • DS18S20函数指令(随后是任何需要的数据交换)

初始化

一线制总线上的所有传输都以初始化序列开始。初始化序列包括一个由总线主站传输的复位脉冲,然后是由从站传输的存在脉冲。存在脉冲让总线主站知道从属设备(如DS18S20)在总线上并准备好操作。复位脉冲和存在脉冲的时间详见单线信号部分。

ROM指令

在总线主站检测到一个存在脉冲后,它可以发出一个ROM命令。这些命令对每个从属设备的独特的64位ROM代码进行操作,如果1-Wire总线上有许多设备存在,主站就可以将其挑出来。这些命令还允许主站确定总线上有多少个设备和哪些类型的设备,或者任何设备是否出现了报警状况。有五条ROM命令,每条命令的长度为8位。主控设备在发出DS18S20功能命令之前,必须先发出一条适当的ROM命令。图14中显示了ROM命令的操作流程图。

搜索 ROM [F0H]

When a system is initially powered up, the master must identify the ROM codes of all slave devices on the bus, which allows the master to determine the number of slaves and their device types. The master learns the ROM codes through a process of elimination that requires the master to perform a Search ROM cycle (i.e., Search ROM command followed by data exchange) as many times as necessary to identify all of the slave devices. If there is only one slave on the bus, the simpler Read ROM command (see below) can be used in place of the Search ROM process. For a detailed explanation of the Search ROM procedure, refer to the iButton ® Book of Standards at www.maxim-ic.com/ibuttonbook. After every Search ROM cycle, the bus master must return to Step 1 (Initialization) in the transaction sequence.

当系统最初上电时,主站必须识别总线上所有从站设备的ROM编码,这使得主站可以确定从站的数量和它们的设备类型。主站通过一个淘汰过程来学习ROM代码,这需要主站执行一个搜索ROM循环(即搜索ROM命令,然后进行数据交换),次数不限,以确定所有的从属设备。如果总线上只有一个从属设备,可以用更简单的Read ROM命令(见下文)来代替Search ROM过程。关于搜索ROM过程的详细解释,请参考iButton ®标准书,网址:www.maxim-ic.com/ibuttonbook。在每个Search ROM周期之后,总线主站必须返回到交易顺序中的步骤1(初始化)。

READ ROM [33h]

This command can only be used when there is one slave on the bus. It allows the bus master to read the slave’s 64-bit ROM code without using the Search ROM procedure. If this command is used when there is more than one slave present on the bus, a data collision will occur when all the slaves attempt to respond at the same time.

这条命令只能在总线上有一个从机时使用。它允许总线主站读取从站的 64 位 ROM 代码,而无需使用搜索 ROM 程序。如果在总线上有多个从机时使用此命令,当所有从机试图同时响应时,将发生数据碰撞。

MATCH ROM [55h]

The match ROM command followed by a 64-bit ROM code sequence allows the bus master to address a specific slave device on a multidrop or single-drop bus. Only the slave that exactly matches the 64-bit ROM code sequence will respond to the function command issued by the master; all other slaves on the bus will wait for a reset pulse.

匹配ROM命令后有一个64位ROM代码序列,允许总线主站在多分叉或单分叉总线上寻址一个特定的从属设备。只有与64位ROM代码序列完全匹配的从属设备才会对主站发出的功能命令作出反应;总线上的所有其他从属设备将等待一个复位脉冲。

SKIP ROM [CCh]

The master can use this command to address all devices on the bus simultaneously without sending out any ROM code information. For example, the master can make all DS18S20s on the bus perform simultaneous temperature conversions by issuing a Skip ROM command followed by a Convert T [44h] command.

主站可以用这个命令同时对总线上的所有设备进行寻址,而不需要发送任何ROM代码信息。例如,主站可以通过发出跳过ROM命令,然后发出Convert T[44h]命令,使总线上的所有DS18S20同时进行温度转换。

Note that the Read Scratchpad [BEh] command can follow the Skip ROM command only if there is a single slave device on the bus. In this case, time is saved by allowing the master to read from the slave without sending the device’s 64-bit ROM code. A Skip ROM command followed by a Read Scratchpad command will cause a data collision on the bus if there is more than one slave since multiple devices will attempt to transmit data simultaneously.

请注意,只有当总线上有一个从属设备时,读高速暂存存储器(Scratchpad)[BEh]命令才能跟随跳过ROM命令。在这种情况下,允许主设备从从属设备中读取,而不发送设备的64位ROM代码,从而节省时间。如果总线上有一个以上的从属设备,跳过ROM命令后跟读高速暂存存储器(Scratchpad)命令将导致总线上的数据碰撞,因为多个设备将试图同时传输数据。

ALARM SEARCH [ECh]

The operation of this command is identical to the operation of the Search ROM command except that only slaves with a set alarm flag will respond. This command allows the master device to determine if any DS18S20s experienced an alarm condition during the most recent temperature conversion. After every Alarm Search cycle (i.e., Alarm Search command followed by data exchange), the bus master must return to Step 1 (Initialization) in the transaction sequence. See the Operation—Alarm Signaling section for an explanation of alarm flag operation.

该命令的操作与搜索ROM命令的操作相同,只是只有设置了报警标志的从机才会响应。该命令允许主设备确定在最近的温度转换过程中是否有任何DS18S20出现了报警情况。在每个报警搜索周期(即报警搜索命令后的数据交换)之后,总线主设备必须返回到数据传输序列中的步骤1(初始化)。有关报警标志操作的解释,请参见操作-报警信号部分。

DS18S20 FUNCTION COMMANDS

CONVERT T [44h]

This command initiates a single temperature conversion. Following the conversion, the resulting thermal data is stored in the 2-byte temperature register in the scratchpad memory and the DS18S20 returns to its low-power idle state. If the device is being used in parasite power mode, within 10μs (max) after this command is issued the master must enable a strong pullup on the 1-Wire bus for the duration of the conversion (t_CONV) as described in the Powering the DS18S20 section. If the DS18S20 is powered by an external supply, the master can issue read-time slots after the Convert T command and the DS18S20 will respond by transmitting 0 while the temperature conversion is in progress and 1 when the conversion is done. In parasite power mode this notification technique cannot be used since the bus is pulled high by the strong pullup during the conversion.

该命令启动了一次温度转换。在转换之后,产生的热数据被存储在scratchpad存储器的2字节温度寄存器中,DS18S20返回到低功耗的空闲状态。如果该器件在寄生电源模式下使用,在该命令发出后的10μs(最大值)内,主控器必须在转换的持续时间(t_CONV)内启用1线总线上的强拉升,如DS18S20供电部分所述。如果DS18S20由外部电源供电,主站可以在Convert T命令后发出 read-time slots,DS18S20将在温度转换过程中发送0,转换完成后发送1。在寄生电源模式下,这种通知技术不能使用,因为总线在转换过程中被强拉高。

WRITE SCRATCHPAD [4Eh]

This command allows the master to write 2 bytes of data to the DS18S20’s scratchpad. The first byte is written into the T_H register (byte 2 of the scratchpad), and the second byte is written into the T_L register (byte 3 of the scratchpad). Data must be transmitted least significant bit first. Both bytes MUST be written before the master issues a reset, or the data may be corrupted.

该命令允许主控端向DS18S20的scratchpad写入2个字节的数据。第一个字节被写入T_H寄存器(刮板的第2字节),第二个字节被写入T_L寄存器(刮板的第3字节)。数据必须先传输最小有效位。两个字节都必须在主站发出复位之前写入,否则数据可能被破坏。

READ SCRATCHPAD [BEh]

This command allows the master to read the contents of the scratchpad. The data transfer starts with the least significant bit of byte 0 and continues through the scratchpad until the 9th byte (byte 8 – CRC) is read. The master may issue a reset to terminate reading at any time if only part of the scratchpad data is needed.

这条命令允许主站读取高速暂存存储器(Scratchpad)的内容。数据传输从第0个字节的最小有效位开始,一直到读取第9个字节(第8个字节-CRC)。如果只需要部分高速暂存存储器(Scratchpad)内容,主站可以在任何时候发出复位以终止读取。

COPY SCRATCHPAD [48h]

This command copies the contents of the scratchpad T_H and T_L registers (bytes 2 and 3) to EEPROM. If the device is being used in parasite power mode, within 10μs (max) after this command is issued the master must enable a strong pullup on the 1-Wire bus for at least 10ms as described in the Powering the DS18S20 section.

该命令将高速暂存存储器(Scratchpad)T_H和T_L寄存器(字节2和3)的内容复制到EEPROM。如果器件在寄生电源模式下使用,在此命令发出后的10μs(最大)内,主控器必须在1-Wire总线上启用一个强的上拉,至少10ms,如DS18S20供电部分所述。

RECALL E^2 [B8h]

This command recalls the alarm trigger values (T_H and T_L ) from EEPROM and places the data in bytes 2 and 3, respectively, in the scratchpad memory. The master device can issue read-time slots following the Recall E^2 command and the DS18S20 will indicate the status of the recall by transmitting 0 while the recall is in progress and 1 when the recall is done. The recall operation happens automatically at power- up, so valid data is available in the scratchpad as soon as power is applied to the device.

该命令从EEPROM中回调报警触发值(T_H和T_L),并将数据分别放在字节2和字节3中的scratchpad存储器中。主设备可以在Recall E^2命令后发出 read-time slots,DS18S20会在回调过程中发送0,在回调完成后发送1,以显示回调的状态。回调操作在上电时自动发生,因此一旦给设备上电,高速暂存存储器(Scratchpad)中的有效数据就可用。

READ POWER SUPPLY [B4h]

The master device issues this command followed by a read-time slot to determine if any DS18S20s on the bus are using parasite power. During the read-time slot, parasite powered DS18S20s will pull the bus low, and externally powered DS18S20s will let the bus remain high. See the Powering the DS18S20 section for usage information for this command.

主设备发出这个命令后,会有一个读时隙,以确定总线上是否有DS18S20在使用寄生电源。在读取时间段内,寄生电源的DS18S20会将总线拉低,而外部电源的DS18S20会让总线保持高电平。有关该命令的使用信息,请参见给DS18S20供电部分。

For parasite-powered DS18S20s, the master must enable a strong pullup on the 1-Wire bus during temperature conversions and copies from the scratchpad to EEPROM. No other bus activity may take place during this time.

对于寄生电源的DS18S20,在温度转换和从scratchpad复制到EEPROM期间,主控器必须在1-Wire总线上启用一个强大的上拉。在这段时间内不得进行其他总线活动。

主站可以在任何时候通过发出复位来中断数据的传输

在发出重置之前,两个字节都必须被写入

1-WIRE SIGNALING

The DS18S20 uses a strict 1-Wire communication protocol to ensure data integrity. Several signal types are defined by this protocol: reset pulse, presence pulse, write 0, write 1, read 0, and read 1. All these signals, with the exception of the presence pulse, are initiated by the bus master.

DS18S20使用严格的单线通信协议以确保数据的完整性。该协议定义了几种信号类型:复位脉冲、存在脉冲、写0、写1、读0和读1。所有这些信号,除了存在脉冲外,都是由总线主站发起的。

INITIALIZATION PROCEDURE—RESET AND PRESENCE PULSES

All communication with the DS18S20 begins with an initialization sequence that consists of a reset pulse from the master followed by a presence pulse from the DS18S20. This is illustrated in Figure 10. When the DS18S20 sends the presence pulse in response to the reset, it is indicating to the master that it is on the bus and ready to operate.

所有与DS18S20的通信都从初始化序列开始,该序列包括一个来自主站的复位脉冲,然后是来自DS18S20的存在脉冲。这在图10中有所说明。当DS18S20为响应复位而发送存在脉冲时,它向主站表示它已经在总线上并准备好操作。

During the initialization sequence the bus master transmits (T_X) the reset pulse by pulling the 1-Wire bus low for a minimum of 480μs. The bus master then releases the bus and goes into receive mode (R_X). When the bus is released, the 5kΩ pullup resistor pulls the 1-Wire bus high. When the DS18S20 detects this rising edge, it waits 15μs to 60μs and then transmits a presence pulse by pulling the 1-Wire bus low for 60μs to 240μs.

在初始化过程中,总线主站通过将1线总线拉低至少480μs来发送(T_X)复位脉冲。然后,总线主站释放总线并进入接收模式(R_X)。 当总线被释放时,5kΩ的上拉电阻将1-Wire总线拉高。当DS18S20检测到这个上升沿时,它等待15μs至60μs,然后通过将1-Wire总线拉低60μs至240μs来传输一个存在脉冲。

READ/WRITE TIME SLOTS

The bus master writes data to the DS18S20 during write time slots and reads data from the DS18S20 during read-time slots. One bit of data is transmitted over the 1-Wire bus per time slot.

总线主站在写时隙向DS18S20写数据,在读时隙从DS18S20读数据。每个时隙在一线制总线上传输一个比特的数据。

WRITE TIME SLOTS

There are two types of write time slots: “Write 1” time slots and “Write 0” time slots. The bus master uses a Write 1 time slot to write a logic 1 to the DS18S20 and a Write 0 time slot to write a logic 0 to the DS18S20. All write time slots must be a minimum of 60μs in duration with a minimum of a 1μs recovery time between individual write slots. Both types of write time slots are initiated by the master pulling the 1-Wire bus low (see Figure 11).

有两种类型的写时隙。”写1 “时隙和 “写0 “时隙。总线主站使用写1时隙向DS18S20写入逻辑1,使用写0时隙向DS18S20写入逻辑0。所有写时隙的持续时间必须至少为60μs,各写时隙之间至少有1μs的恢复时间。这两种类型的写时隙都是由主控器将1-Wire总线拉低启动的(见图11)。

To generate a Write 1 time slot, after pulling the 1-Wire bus low, the bus master must release the 1-Wire bus within 15μs. When the bus is released, the 5kΩ pullup resistor will pull the bus high. To generate a Write 0 time slot, after pulling the 1-Wire bus low, the bus master must continue to hold the bus low for the duration of the time slot (at least 60μs). The DS18S20 samples the 1-Wire bus during a window that lasts from 15μs to 60μs after the master initiates the write time slot. If the bus is high during the sampling window, a 1 is written to the DS18S20. If the line is low, a 0 is written to the DS18S20.

要产生一个写1的时隙,在拉低1-Wire总线后,总线主站必须在15μs内释放1-Wire总线。当总线被释放时,5kΩ的上拉电阻将把总线拉高。要产生一个写0的时隙,在拉低1-Wire总线后,总线主站必须在时隙的持续时间内(至少60μs)继续保持总线低电平。DS18S20在主站启动写时隙后的15μs至60μs的窗口内对1-Wire总线进行采样。如果总线在采样窗口期间为高电平,则向DS18S20写入一个1。如果线路为低电平,则向DS18S20写入一个0。

READ-TIME SLOTS

The DS18S20 can only transmit data to the master when the master issues read-time slots. Therefore, the master must generate read-time slots immediately after issuing a Read Scratchpad [BEh] or Read Power Supply [B4h] command, so that the DS18S20 can provide the requested data. In addition, the master can generate read-time slots after issuing Convert T [44h] or Recall E 2 [B8h] commands to find out the status of the operation as explained in the DS18S20 Function Commands section.

DS18S20只有在主站发出读时隙时才能向主站传输数据。因此,主站必须在发出Read Scratchpad [BEh]或Read Power Supply [B4h]命令后立即产生读时隙,以便DS18S20能够提供所要求的数据。此外,主站可以在发出Convert T [44h]或Recall E 2 [B8h]命令后产生读时隙,以了解操作的状态,这在DS18S20功能命令部分有说明。

All read-time slots must be a minimum of 60μs in duration with a minimum of a 1μs recovery time between slots. A read-time slot is initiated by the master device pulling the 1-Wire bus low for a minimum of 1μs and then releasing the bus (see Figure 11). After the master initiates the read-time slot, the DS18S20 will begin transmitting a 1 or 0 on bus. The DS18S20 transmits a 1 by leaving the bus high and transmits a 0 by pulling the bus low. When transmitting a 0, the DS18S20 will release the bus by the end of the time slot, and the bus will be pulled back to its high idle state by the pullup resister. Output data from the DS18S20 is valid for 15μs after the falling edge that initiated the read-time slot. Therefore, the master must release the bus and then sample the bus state within 15μs from the start of the slot.

所有读时隙的持续时间必须至少为60μs,各时隙之间至少有1μs的恢复时间。一个读时隙是由主设备将1-Wire总线拉低至少1μs,然后释放总线而启动的(见图11)。在主设备启动读时隙后,DS18S20将开始在总线上传输一个1或0。DS18S20通过让总线保持高电平来传输1,通过将总线拉低来传输0。当传输0时,DS18S20将在时隙结束前释放总线,总线将被上拉电阻拉回到高电平空闲状态。DS18S20的输出数据在启动读时隙的下降沿后15μs内有效。因此,主站必须释放总线,然后在时隙开始后的15μs内采样总线状态。

DS18S20 OPERATION EXAMPLE 1

In this example there are multiple DS18S20s on the bus and they are using parasite power. The bus master initiates a temperature conversion in a specific DS18S20 and then reads its scratchpad and recalculates the CRC to verify the data.

在这个例子中,总线上有多个DS18S20,它们正在使用寄生电源。总线主站在一个特定的DS18S20中启动温度转换,然后读取它的刮板,重新计算CRC以验证数据。

综述

The DS18S20 uses Maxim’s exclusive 1-Wire bus protocol that implements bus communication using one control signal. The control line requires a weak pullup resistor since all devices are linked to the bus via a 3-state or open-drain port (the DQ pin in the case of the DS18S20). In this bus system, the microprocessor (the master device) identifies and addresses devices on the bus using each device’s unique 64-bit code. Because each device has a unique code, the number of devices that can be addressed on one bus is virtually unlimited. The 1-Wire bus protocol, including detailed explanations of the commands and “time slots,” is covered in the 1-Wire Bus System section.

DS18S20采用Maxim独有的1-Wire总线协议,利用一个控制信号实现总线通信。该控制线需要一个弱的上拉电阻,因为所有器件都通过一个3态或开漏端口(DS18S20的DQ引脚)连接到总线上。在这个总线系统中,微处理器(主设备)使用每个设备独特的64位代码来识别和寻址总线上的设备。因为每个设备都有一个唯一的代码,所以在一条总线上可以寻址的设备数量几乎是无限的。一线制总线协议,包括对命令和 “时隙 “的详细解释,将在一线制总线系统部分介绍。

Another feature of the DS18S20 is the ability to operate without an external power supply. Power is instead supplied through the 1-Wire pullup resistor via the DQ pin when the bus is high. The high bus signal also charges an internal capacitor (C_PP ), which then supplies power to the device when the bus is low. This method of deriving power from the 1-Wire bus is referred to as “parasite power.” As an alternative, the DS18S20 may also be powered by an external supply on V_DD .

DS18S20的另一个特点是能够在没有外部电源的情况下工作。当总线为高电平时,电源通过DQ引脚的1线上拉电阻提供。高总线信号也给一个内部电容(C_PP)充电,然后当总线为低电平时,该电容向器件供电。这种从一线制总线获取电源的方法被称为 “寄生电源”。作为一种选择,DS18S20也可以由V_DD上的外部电源供电。

OPERATION—MEASURING TEMPERATURE

The core functionality of the DS18S20 is its direct-to-digital temperature sensor. The temperature sensor output has 9-bit resolution, which corresponds to 0.5°C steps. The DS18S20 powers-up in a low-power idle state; to initiate a temperature measurement and A-to-D conversion, the master must issue a Convert T [44h] command. Following the conversion, the resulting thermal data is stored in the 2-byte temperature register in the scratchpad memory and the DS18S20 returns to its idle state. If the DS18S20 is powered by an external supply, the master can issue “read-time slots” (see the 1-Wire Bus System section) after the Convert T command and the DS18S20 will respond by transmitting 0 while the temperature conversion is in progress and 1 when the conversion is done. If the DS18S20 is powered with parasite power, this notification technique cannot be used since the bus must be pulled high by a strong pullup during the entire temperature conversion. The bus requirements for parasite power are explained in detail in the Powering the DS18S20 section.

DS18S20的核心功能是其直接数字式温度传感器。温度传感器输出具有9位分辨率,相当于0.5°C步长。DS18S20在低功耗空闲状态下上电;要启动温度测量和A-D转换,主站必须发出Convert T [44h]命令。在转换之后,产生的热数据被存储在刮板存储器的2字节温度寄存器中,DS18S20返回到空闲状态。如果DS18S20由外部电源供电,主站可以在Convert T命令后发出 “读时隙”(参见1线总线系统部分),DS18S20将在温度转换过程中发送0,转换完成后发送1,从而做出响应。如果DS18S20使用寄生电源供电,则不能使用这种通知技术,因为在整个温度转换过程中,总线必须被强拉高。关于寄生电源的总线要求,在DS18S20的供电部分有详细解释。

The DS18S20 output data is calibrated in degrees centigrade; for Fahrenheit applications, a lookup table or conversion routine must be used. The temperature data is stored as a 16-bit sign-extended two’s complement number in the temperature register (see Figure 2). The sign bits (S) indicate if the temperature is positive or negative: for positive numbers S = 0 and for negative numbers S = 1. Table 1 gives examples of digital output data and the corresponding temperature reading.

DS18S20输出数据以摄氏度为单位进行校准;对于华氏温度应用程序,必须使用查找表或转换例程。温度数据作为16位符号扩展二的补码存储在温度寄存器中(见图2)。符号位表示温度是正还是负:对于正数S=0,对于负数S=1。表1给出了数字输出数据和相应温度读数的示例。

Resolutions greater than 9 bits can be calculated using the data from the temperature, COUNT REMAIN and COUNT PER °C registers in the scratchpad. Note that the COUNT PER °C register is hard-wired to 16 (10h). After reading the scratchpad, the TEMP_READ value is obtained by truncating the 0.5°C bit (bit 0) from the temperature data (see Figure 2). The extended resolution temperature can then be calculated using the following equation:

大于9位的分辨率可以使用刮板中的温度、COUNT REMAIN和COUNT PER °C寄存器的数据进行计算。请注意,COUNT PER °C 寄存器被硬连接为16(10h)。读取刮板后,通过截断温度数据中的0.5°C位(第0位)得到TEMP_READ值(见图2)。然后可以用以下公式计算扩展分辨率的温度。

OPERATION—ALARM SIGNALING

After the DS18S20 performs a temperature conversion, the temperature value is compared to the user defined two’s complement alarm trigger values stored in the 1-byte T_H and T_L registers (see Figure 3). The sign bit (S) indicates if the value is positive or negative: for positive numbers S = 0 and for negative numbers S = 1. The T_H and T_L registers are nonvolatile (EEPROM) so they will retain data when the device is powered down. T_H and T_L can be accessed through bytes 2 and 3 of the scratchpad as explained in the Memory section.

在DS18S20执行温度转换后,温度值与存储在1字节的T_H和T_L寄存器中的用户定义的二补码报警触发值进行比较(见图3)。 符号位(S)表示该值是正数还是负数:对于正数S=0,对于负数S=1。T_H和T_L寄存器是非易失性的(EEPROM),所以当设备断电时,它们会保留数据。T_H和T_L可以通过刮板的第2和第3字节进行访问,这在存储器部分有说明。

Only bits 8 through 1 of the temperature register are used in the T_H and T_L comparison since T_H and T_L are 8-bit registers. If the measured temperature is lower than or equal to T_L or higher than T_H , an alarm condition exists and an alarm flag is set inside the DS18S20. This flag is updated after every temperature measurement; therefore, if the alarm condition goes away, the flag will be turned off after the next temperature conversion.

由于T_H和T_L是8位寄存器,所以在T_H和T_L的比较中只使用温度寄存器的第8位到第1位。如果测量的温度低于或等于T_L或高于T_H,则存在一个报警条件,并在DS18S20内部设置一个报警标志。该标志在每次温度测量后更新;因此,如果报警条件消失,该标志将在下一次温度转换后被关闭。

The master device can check the alarm flag status of all DS18S20s on the bus by issuing an Alarm Search [ECh] command. Any DS18S20s with a set alarm flag will respond to the command, so the master can determine exactly which DS18S20s have experienced an alarm condition. If an alarm condition exists and the T H or T L settings have changed, another temperature conversion should be done to validate the alarm condition.

主控设备可以通过发出Alarm Search [ECH] 命令来检查总线上所有DS18S20的报警标志状态。任何设置了报警标志的DS18S20都会响应该命令,因此主设备可以准确地确定哪些DS18S20出现了报警状况。如果存在报警条件,并且T H或T L设置发生了变化,应再次进行温度转换以验证报警条件。

64-BIT LASERED ROM CODE

Each DS18S20 contains a unique 64-bit code (see Figure 6) stored in ROM. The least significant 8 bits of the ROM code contain the DS18S20’s 1-Wire family code: 10h. The next 48 bits contain a unique serial number. The most significant 8 bits contain a cyclic redundancy check (CRC) byte that is calculated from the first 56 bits of the ROM code. A detailed explanation of the CRC bits is provided in the CRC Generation section. The 64-bit ROM code and associated ROM function control logic allow the DS18S20 to operate as a 1-Wire device using the protocol detailed in the 1-Wire Bus System section.

每个DS18S20都有一个独特的64位代码(见图6),存储在ROM中。ROM代码中最不重要的8位包含了DS18S20的1-Wire系列代码:10h. 接下来的48位包含一个独特的序列号。最有意义的8位包含一个循环冗余校验(CRC)字节,这个字节是由ROM代码的前56位计算出来的。关于CRC位的详细解释见CRC生成部分。64位ROM代码和相关的ROM功能控制逻辑允许DS18S20作为一个单线设备使用单线总线系统部分详述的协议运行。

MEMORY

The DS18S20’s memory is organized as shown in Figure 7. The memory consists of an SRAM scratchpad with nonvolatile EEPROM storage for the high and low alarm trigger registers (T H and T L ). Note that if the DS18S20 alarm function is not used, the T H and T L registers can serve as general-purpose memory. All memory commands are described in detail in the DS18S20 Function Commands section. Byte 0 and byte 1 of the scratchpad contain the LSB and the MSB of the temperature register,respectively.

DS18S20的内存组织如图7所示。该存储器由SRAM刮板和非易失性EEPROM组成,用于存储高、低报警触发寄存器(T H和T L )。 请注意,如果不使用DS18S20的报警功能,T H和T L寄存器可以作为通用的存储器。所有的内存命令都在DS18S20功能命令部分有详细的描述。 刮板的第0字节和第1字节分别包含温度寄存器的LSB和MSB。

These bytes are read-only. Bytes 2 and 3 provide access to T H and T L registers. Bytes 4 and 5 are reserved for internal use by the device and cannot be overwritten; these bytes will return all 1s when read. Bytes 6 and 7 contain the COUNT REMAIN and COUNT PER ºC registers, which can be used to calculate extended resolution results as explained in the Operation—Measuring Temperature section.

这些字节是只读的。字节2和3提供对T H和T L寄存器的访问。字节4和5保留给设备内部使用,不能被覆盖;这些字节在读取时将返回所有的1。字节6和7包含COUNT REMAIN和COUNT PER ºC寄存器,可用于计算扩展的分辨率结果,如操作-测量温度一节中所解释的。