EFM32片内外设--LCD之动画

一直知道EFM32的LCD Controller支持简单的动画效果,而不需要MCU去参与。但是一直没有时间来给这个功能做一个总结。抽空总结一下,因此在TG STK的基础上,详细的说明一下,免得自己时间久了忘记。最终的效果如下:

 

注:Gecko显示不全,是因为PE13被我断开了了。用来测试EM4 GPIO唤醒用了。

 

LCD Controller控制器支持动画状态机,可以在低功耗状态下,自动更新LCD的显示界面,而无需MCU干预。但是LCD Controller并不能将所有的LCD Segment都动画,目前仅支持LCD_COM0上的Segmeng0~Segment7.以TG STK为例,它就是将LCD左上角的那个圈圈连接到了LCD_COM0的Segmeng0~Segmeng7.如下图所示:

        图1: 圈圈为A0~A7,可能不太清晰

     图2:对应到真值表,说明A0~A7是连接到LCD屏的COM7上的

   图3:而实际的连线却是,MCU的COM0(PE4)连接着LCD屏的COM7,反着接的

 

 

动画效果的实现是通过两个8bit的寄存器即LCD_AREGA,LCD_AREGB的左移或右移来实现的,因此总共可以有16种状态。左移和右移,是通过寄存器LCD_BACTRL中的AREGASC和AREGBSC来分别控制的。另外,Frame Conter也必须使能。总共有三种方式,不移动,左移与右移。另外,可以控制LCD_AREGA,LCD_AREGB的的逻辑关系,来最终获得显示的值。逻辑关系包括逻辑与,逻辑或。

在本例子当中,LCD_AREGA初始值为0x01,采用右移的方式,LCD_AREGB初始值为0x00, 不移动,两者的关系为逻辑或。

因此,到现在为止,我们应该清楚了,实现动画效果是有一定的硬件上的限制,并且也知道了其实动画效果是通过两个8bit寄存器的逻辑关系来获得的。剩下的就是这几个寄存器是受谁控制的,如何去配置的问题了。

目前清楚的是,这个动画的功能肯定受LCD Controller控制,但是如何操作呢?

 

1.首先,初始化LCD Controller. 如果不想自己写,则可以segmenglcd.c中的SegmentLCD_Init(false)函数。

void SegmentLCD_Init(bool useBoost)
{
  const LCD_Init_TypeDef lcdInit = { true,
                                     lcdMuxOctaplex,
                                     lcdBiasOneFourth,
                                     lcdWaveLowPower,
                                     lcdVLCDSelVDD,
                                     lcdConConfVLCD };

  /* Ensure LE modules are accessible */
  CMU_ClockEnable(cmuClock_CORELE, true);

  /* Enable LFRCO as LFACLK in CMU (will also enable oscillator if not enabled) */
  CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);

  /* LCD Controller Prescaler (divide LFACLK / 64) */
  CMU_ClockDivSet(cmuClock_LCDpre, cmuClkDiv_64);
  /* LFACLK_LCDpre = 512 Hz */
  CMU_LCDClkFDIVSet(cmuClkDiv_1);
  /* Set FDIV=0, means 512/1 = 512 Hz */
  /* With octaplex mode, 512/16 => 32 Hz Frame Rate */

  /* Enable clock to LCD module */
  CMU_ClockEnable(cmuClock_LCD, true);

  /* Disable interrupts */
  LCD_IntDisable(0xFFFFFFFF);

  /* Initialize and enable LCD controller */
  LCD_Init(&lcdInit);

  /* Enable all display segments */
  LCD_SegmentRangeEnable(lcdSegmentAll, true);
  /* Enable boost if necessary */
  if (useBoost)
  {
    LCD_VBoostSet(lcdVBoostLevel3);
    LCD_VLCDSelect(lcdVLCDSelVExtBoost);
    CMU->LCDCTRL |= CMU_LCDCTRL_VBOOSTEN;
  }

  /* Turn all segments off */
  SegmentLCD_AllOff();

  LCD_SyncBusyDelay(0xFFFFFFFF);
}

 

2.除了基本的初始化,还需要初始化Frame Counter。 Frame Conter是何东东,他是用来同步LCD的帧起始进行帧计数,其实这就是一个帧计数器,计到设定的值,就产生更新的事件,我们这里就是更新LCD的动画显示。

既然是一个帧计数器,那么就需要他的时钟源,以及动画更新的时间间隔是如何计算的。

首先,动画的时间CLKevent间隔计算如下:

通过29.2这条公式,我们知道,事件产生的频率是受到CLKfc控制的,是(1+FCTOP)分之CLKfc,此处的fc = Frame Counter

而CLKfc 的时钟来源于LCD Controller的Frame时钟

可以通过设置FCPRESC来配置CLKfc与CLKframe的关系。

而CLKframe则等于LFACLKLCD的时钟频率有关。如果是配制成8COM的话,CLKframe = LFACLKLCD/16

而LFACLKLCD的时钟源,又是取自哪里呢?参看如下的公式,取自LFACLKLCDpre

而LFACLKlcdpre的时钟则来源于:哦哦,来自于LFACLK.

终于理清了这里的时钟关系。难怪说,芯片里面最复杂的是时钟系统。我靠,仅仅是个LCD自动动画的功能,涉及到的时钟源就有足足6个之多。下次在计算时间的时候,我会从下我上看的。。呵呵。

 

最后,我们来上一段小代码吧.

 

#include <stdint.h>
#include <stdbool.h>
#include "efm32.h"
#include "em_chip.h"
#include "em_emu.h"
#include "em_lcd.h"
#include "segmentlcd.h"

/* LCD Animation Configuration */
LCD_AnimInit_TypeDef animInit =
{
  .enable    = true,                /* Enable Animation at end of initialization */
  .AReg      = 0x01,                /* Initial Animation Register A Value */
  .AShift    = lcdAnimShiftRight,   /* Shift operation of Animation Register A */
  .BReg      = 0x00,                /* Initial Animation Register B Value */
  .BShift    = lcdAnimShiftNone,    /* Shift operation of Animation Register B */
  .animLogic = lcdAnimLogicOr,      /* A and B Logical Operation to use for mixing and outputting resulting segments */
};

/* LCD Frame Control Initialization */
LCD_FrameCountInit_TypeDef fcInit =
{
  .enable   = true,              /* Enable at end */
  .top      = 4,                 /* Frame Counter top value */
  .prescale = lcdFCPrescDiv1,    /* Frame Counter clock prescaler */
};


void startLCDAnimation(void)
{
  /* Show animation */
  LCD_AnimInit(&animInit);

  /* Configure LCD to give a frame counter interrupt every 8th frame. */
  LCD_FrameCountInit(&fcInit);
  LCD_SyncBusyDelay(LCD_SYNCBUSY_BACTRL);
}

int main(void)
{
  /* Chip errata */
  CHIP_Init();
 
  /* Enable LCD without voltage boost */
  SegmentLCD_Init(false);
  SegmentLCD_Write(" Gecko ");
 
  startLCDAnimation();

  while(1)
  {
      EMU_EnterEM2(false);
  }
}

而实现这样的动画功能,付出的功耗,仅仅为2.25uA左右。如果应用在智能仪表领域,用动画的功能,就可以不停的向用户提示,我还在工作,还在工作。呵呵。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值