韵湖葱白 发表于 2022-5-10 18:43

【AT-START-F425测评】No.06 驱动段码LCD


## 前言

还是之前折腾GD32L233时弄的一块SLCD屏,改吧改吧就在AT32F425上跑起来了。

板子其实比较简单,打板如下:

!(https://s2.loli.net/2022/04/29/HxmlgykbJecN7P6.jpg)

其中:

信号管脚RC参数中的R参数以及VLCD的分压电阻可直接参考手册。

## 如何测试裸屏

裸屏是交流信号驱动,直接用DC是不行的,得用交流测试。

用一段线缠绕在交流线上面,就可以测试了。

!(https://s2.loli.net/2022/05/10/C4mtpsQLWK28OIP.jpg)

![测试结果](https://s2.loli.net/2022/05/10/EFCKSTOeohmJVQp.gif)

## 段码液晶的原理

!(https://s2.loli.net/2022/04/29/D3SCYnfdzHgcbV2.jpg)

其中最关键的驱动条件参数,一般而言:

- duty = 1/com的数量
- bias = 1/(sqrt(duty)+1)

!(https://s2.loli.net/2022/04/29/iTLJMCdQWXFr8R9.jpg)

SLCD按duty的周期执行扫描模式,所以简单的理解:

- SEG = 地址
- COM = 数据

---

假如我们需要显示第一位的数字为2,那么对应的【8】,其中:标号2,标号3,标号4,标号6,标号7会亮。

参考SEG图,我们知道:

- SEG 9对应的是标号1,标号2,标号3,标号4共4段。
- SEG 10对应的是标号5,标号6,标号7共3段(电池图标我们不用)。

要想把标号2,标号3,标号4,标号6,标号7点亮,那么:

- SEG 9:COM0(标号4),COM1(标号3),COM2(标号2)为1。
- SEG 10:COM2(标号3),COM3(标号2)为1。

就是下表:

|| COM0 | COM1 | COM2 | COM3 |
| --- | --- | --- | --- | --- |
| SEG9 | 1 | 1 | 1 | 0 |
| SEG10 | 0 | 0 | 1 | 1 |

也就是往这两个地址写入0xE和0x3就能显示数字2。

懂了啵?!

## AT32的GPIO口

只说跟STM32、GD32的差异性吧。

### GPIO的驱动能力

是定义了2个宏定义。

```
GPIO_DRIVE_STRENGTH_STRONGER         = 0x01, /*!< stronger sourcing/sinking strength */
GPIO_DRIVE_STRENGTH_MODERATE         = 0x02/*!< moderate sourcing/sinking strength */
```

### GPIO的复用

又单独给每个管脚定义了SOURCE,封装起来又多了一个函数。

GPIO的封装接口:

```
static gpio_pins_source_type get_gpio_pins_source(uint32_t pin)
{
    switch (pin)
    {
      case GPIO_PINS_0:
            return GPIO_PINS_SOURCE0;
      case GPIO_PINS_1:
            return GPIO_PINS_SOURCE1;
      case GPIO_PINS_2:
            return GPIO_PINS_SOURCE2;
      case GPIO_PINS_3:
            return GPIO_PINS_SOURCE3;
      case GPIO_PINS_4:
            return GPIO_PINS_SOURCE4;
      case GPIO_PINS_5:
            return GPIO_PINS_SOURCE5;
      case GPIO_PINS_6:
            return GPIO_PINS_SOURCE6;
      case GPIO_PINS_7:
            return GPIO_PINS_SOURCE7;
      case GPIO_PINS_8:
            return GPIO_PINS_SOURCE8;
      case GPIO_PINS_9:
            return GPIO_PINS_SOURCE9;
      case GPIO_PINS_10:
            return GPIO_PINS_SOURCE10;
      case GPIO_PINS_11:
            return GPIO_PINS_SOURCE11;
      case GPIO_PINS_12:
            return GPIO_PINS_SOURCE12;
      case GPIO_PINS_13:
            return GPIO_PINS_SOURCE13;
      case GPIO_PINS_14:
            return GPIO_PINS_SOURCE14;
      case GPIO_PINS_15:
            return GPIO_PINS_SOURCE15;
      default:
            return GPIO_PINS_SOURCE0;
    }
}

void gpio_init_af_mode(crm_periph_clock_type rcu, gpio_type * gpio, uint32_t pin, uint32_t speed, uint32_t af_func)
{
    gpio_init_type gpio_init_struct;
    crm_periph_clock_enable(rcu, TRUE);
    gpio_default_para_init(&gpio_init_struct);
    gpio_init_struct.gpio_drive_strength = (gpio_drive_type)speed;
    gpio_init_struct.gpio_out_type= GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
    gpio_init_struct.gpio_pins = pin;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init(gpio, &gpio_init_struct);
    gpio_pin_mux_config(gpio, get_gpio_pins_source(pin), (gpio_mux_sel_type)af_func);
}

void gpio_init_output_mode(crm_periph_clock_type rcu, gpio_type * gpio, uint32_t pin, uint32_t speed, uint8_t set)
{
    gpio_init_type gpio_init_struct;
    crm_periph_clock_enable(rcu, TRUE);
   
    gpio_default_para_init(&gpio_init_struct);
    gpio_init_struct.gpio_drive_strength = (gpio_drive_type)speed;
    gpio_init_struct.gpio_out_type= GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
    gpio_init_struct.gpio_pins = pin;
    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
    gpio_init(gpio, &gpio_init_struct);
    if (set)
    {
      gpio_bits_set(gpio, pin);
    }
    else
    {
      gpio_bits_reset(gpio, pin);
    }
}
```

## 驱动代码

一堆寄存器配置,参见芯片手册。

偷个懒,一把贴出来了。

【说明】SLCD切换的时序很短,延时直接用计数--就好。

这个代码跟GD32L233的代码几乎一致,只是定义的管脚和接口宏定义变了,这就是架构提前设计好的好处。


```
//#define SLCD_USING_SPI

#if defined(SPI1_FOR_SLCD)

/* SPI1:PB13-SCK-SPI_SCK PB14-CE-SPI_MISO PB15-DATA-SPI_MOSI */

#define CURRENT_SPI   SPI1
#define CURRENT_SPI_RCU RCU_SPI1

#define SLCD_RCU         CRM_GPIOB_PERIPH_CLOCK
#define SLCD_GPIO      GPIOB
#define SLCD_WR_CLK_PINGPIO_PINS_13
#define SLCD_CS_PIN      GPIO_PINS_14
#define SLCD_DATA_PIN    GPIO_PINS_15

#ifdef SLCD_USING_SPI
#else

#define CS_HIGH   gpio_bits_set(SLCD_GPIO, SLCD_CS_PIN);
#define CS_LOW      gpio_bits_reset(SLCD_GPIO, SLCD_CS_PIN);
#define WR_CLK_HIGH gpio_bits_set(SLCD_GPIO, SLCD_WR_CLK_PIN);
#define WR_CLK_LOWgpio_bits_reset(SLCD_GPIO, SLCD_WR_CLK_PIN);
#define DATA_HIGH   gpio_bits_set(SLCD_GPIO, SLCD_DATA_PIN);
#define DATA_LOW    gpio_bits_reset(SLCD_GPIO, SLCD_DATA_PIN);
#define DATA      gpio_input_data_bit_read(SLCD_GPIO, SLCD_DATA_PIN)

#endif

// SLCD命令码
#defineCTRL_CMD   0x80//写控制命令
#defineDATA_CMD   0xA0//写数据命令

#define LCD_ON   0x06//打开LCD 1000 0000 011x
#define LCD_OFF    0x04//关闭LCD 1000 0000 010x
#define SYS_EN   0x02//系统振荡器开 1000 0000 001x
#define RC_OSC   0x30//内部RC振荡器(上电默认256K) 1000 0011 0XXX
#define COM_BIAS   0x52//4COM,1/3bias 1000 010 10X1X

#define SLCD_OFF      send_cmd_slcd(LCD_OFF)
#define SLCD_ON         send_cmd_slcd(LCD_ON)
#define SLCD_SYS_EN   send_cmd_slcd(SYS_EN)
#define SLCD_RC_OSC   send_cmd_slcd(RC_OSC)
#define SLCD_COM_BIAS   send_cmd_slcd(COM_BIAS)


//,C,c,d,E,F,H,h,L,n,N,o,P,r,t,U,-, ,*/          
//,,0x1D,0x0E,0x6E,0x1F,0x17,0x67,0x47,0x0D,0x46,0x75,0x37,
#define DISP_0      0xD7
#define DISP_1      0x06
#define DISP_2      0xE3
#define DISP_3      0xA7
#define DISP_4      0x36
#define DISP_5      0xB5
#define DISP_6      0xF5
#define DISP_7      0x07
#define DISP_8      0xF7
#define DISP_9      0xB7
#define DISP_A      0x77
#define DISP_B      0xF7
#define DISP_b      0xF4
#define DISP_C      0xD1
#define DISP_D      0xD7
#define DISP_c      0xE0
#define DISP_d      0xE6
#define DISP_E      0xF1
#define DISP_F      0x71
#define DISP_H      0x76
#define DISP_h      0x74
#define DISP_L      0xD0
#define DISP_n      0x64
#define DISP_N      0x57
#define DISP_o      0xE4
#define DISP_P      0x73
#define DISP_r      0x60
#define DISP_t      0xF0
#define DISP_U      0xD6
#define DISP__      0x20
#define DISP_EMPTY0x00

void spi5_init(){}

#ifdef SLCD_USING_SPI

void spi1_init()
{
}

#else

void spi1_init() {
    gpio_init_output_mode(SLCD_RCU, SLCD_GPIO, SLCD_WR_CLK_PIN,GPIO_DRIVE_STRENGTH_MODERATE, 0);
    gpio_init_output_mode(SLCD_RCU, SLCD_GPIO, SLCD_CS_PIN,GPIO_DRIVE_STRENGTH_MODERATE, 0);
    gpio_init_output_mode(SLCD_RCU, SLCD_GPIO, SLCD_DATA_PIN,GPIO_DRIVE_STRENGTH_STRONGER, 0);
}

static void slcd_delay(int count) {
        while (count) {
                count--;
        }
}

void send_bit_slcd(uint8_t sdat, uint8_t cnt)
{
    //data 的高cnt位写入,高位在前
        uint8_t i;
        for(i = 0; i < cnt; i++)
        {
                WR_CLK_LOW;
                slcd_delay(20);
                if(sdat&0x80)
                {
                        DATA_HIGH;
                }
                else
                {
                        DATA_LOW;
                }
                slcd_delay(20);
                WR_CLK_HIGH;
                slcd_delay(20);
                sdat<<=1;
        }
        slcd_delay(20);
}

void send_cmd_slcd(uint8_t command)
{
    //发送指令
        CS_LOW;
        send_bit_slcd(CTRL_CMD, 4);   //写入标志码b100
        send_bit_slcd(command, 8);   //没有最高位为1的命令,直接将command的最高位写0
        CS_HIGH;
}

void write_slcd(uint8_t addr, uint8_t sdat)
{
        addr<<=2;
        CS_LOW;
        send_bit_slcd(DATA_CMD, 3);   //写入标志码b101
        send_bit_slcd(addr, 6);   //写入addr 的高6位
        send_bit_slcd(sdat, 8);   //写入data 的8位
        CS_HIGH;
}


void slcd_user_init(void)
{
    SLCD_OFF;
    SLCD_SYS_EN;
        SLCD_RC_OSC;   
        SLCD_COM_BIAS;
    SLCD_ON;
    slcd_display_data(DISP_0,DISP_0,DISP_0,DISP_0,DISP_0,DISP_0);delay_ms(600);
    slcd_display_data(DISP_1,DISP_1,DISP_1,DISP_1,DISP_1,DISP_1);delay_ms(600);
    slcd_display_data(DISP_2,DISP_2,DISP_2,DISP_2,DISP_2,DISP_2);delay_ms(600);
    slcd_display_data(DISP_3,DISP_3,DISP_3,DISP_3,DISP_3,DISP_3);delay_ms(600);
    slcd_display_data(DISP_4,DISP_4,DISP_4,DISP_4,DISP_4,DISP_4);delay_ms(600);
    slcd_display_data(DISP_5,DISP_5,DISP_5,DISP_5,DISP_5,DISP_5);delay_ms(600);
    slcd_display_data(DISP_6,DISP_6,DISP_6,DISP_6,DISP_6,DISP_6);delay_ms(600);
    slcd_display_data(DISP_7,DISP_7,DISP_7,DISP_7,DISP_7,DISP_7);delay_ms(600);
    slcd_display_data(DISP_8,DISP_8,DISP_8,DISP_8,DISP_8,DISP_8);delay_ms(600);
    slcd_display_data(DISP_9,DISP_9,DISP_9,DISP_9,DISP_9,DISP_9);delay_ms(600);
    slcd_display_data(DISP__,DISP__,DISP__,DISP__,DISP__,DISP__);delay_ms(600);
    slcd_display_data(DISP_H,DISP_E,DISP_L,DISP_L,DISP_0,DISP_EMPTY);
}

void slcd_display_data(uint8_t data1, uint8_t data2, uint8_t data3, uint8_t data4, uint8_t data5, uint8_t data6)
{
    uint8_t addr = 9;
    write_slcd(addr, data1);
    addr += 2;
    write_slcd(addr, data2);
    addr += 2;
    write_slcd(addr, data3);
    addr += 2;
    write_slcd(addr, data4);
    addr += 2;
    write_slcd(addr, data5);
    addr += 2;
    write_slcd(addr, data6);
    addr += 2;
}
#endif
#endif
```

## 视频

![](https://s2.loli.net/2022/05/10/kxR7XlJSdHLmV2g.gif)

![](https://s2.loli.net/2022/03/28/xnJPMjvEfwHs1IS.gif)

lugl4313820 发表于 2022-5-10 21:56

有空测测这段码评的功耗如何呀。
页: [1]
查看完整版本: 【AT-START-F425测评】No.06 驱动段码LCD