(AVR开发)模拟SPI驱动HT16D35A

一、硬件

数码管连接

刚好有一个项目用的是HT16D35A作为数码管驱动,记个笔记,防止遗忘,同时单片机用的是AVR。数码管是共阴极。

看数据手册,HT16D35A使用的是SPI/IIC总线驱动,在PCB布板的时候,考虑到布线难度,并没有使用内部的SPI/IIC,而是采用的模拟方式。

因为应用场合并不需要特别的高效,反而需要持久运行,所以整个单片机程序结构使用的是状态机方式编写,而不是事件驱动或者是时间片轮询的写法。

在手册中截了一张HT16D35A的内部结构

所以整个硬件布局是数码管的COM(公共端)连接到ROW端上,如果是共阳极就接到COM与COM连起来。下面是其中一个数码管的连接,在这个项目有十个数码管。

                         

因为数码管本身就是七个LED,正极对应a~h。所以也可以将多个LED的负极连接到a~h,将它们的正极连接到ROW上。这次的笔记重点也就是这两部分:数码管驱动、LED驱动。

电路图如下,LED的型号是2835红色灯,封装SMD2835,立创是大头为正,拿到样品后,先用万用表二极管档检查,能否点亮,避免正反搞错(PS:前人搞错过)。数码管也是,用二极管档检查COM口的位置是否无误(有的是对角是COM口,有的是38号角是COM口,原理图、PCB画错基本上板子废了,而且最少耽误一周),以及是否是共阳或者共阴。下面左图是2835连接到HT16D35A,右图是2835封装。

确定极限参数

1、HT16D35A输出电流

2、2835最大电流

所以无需增加电阻。其实HT16D35A也可以用R_EXT引脚调整电流大小。后面再写。

HT16D35A引脚部分,与单片机连接。

看了一下数据手册,HT16D

CSB:I2C接口设备地址数据输入引脚/SPI 片选信号

SDA/DIO:串行数据输入 / 输出引脚。

OSC:系统振荡器输入 / 输出引脚。IRC模式才会用的到。

说人话:

  • IRC(Internal RC)是指内部 RC(Resistor-Capacitor)振荡器,它是芯片内部集成的一个振荡器,用于产生系统时钟信号。
  • ERC(External RC)是指外部 RC 振荡器,它是由外部器件提供的一个振荡器,同样用于产生系统时钟信号。
  • 引脚OSC是一个I/O类型的引脚,既可以作为输入也可以作为输出。
  • 当使用IRC模式命令时,系统时钟信号来自于芯片内部的RC振荡器,并且可以通过引脚OSC输出。换句话说,系统时钟是由芯片内部的RC振荡器提供的,并且可以通过引脚OSC输出给外部其他设备使用。
  • 当使用从机模式或ERC模式命令时,系统时钟信号来自于引脚OSC上连接的外部时钟。这意味着系统时钟是由外部器件提供的,并且通过引脚OSC输入到芯片中。
  • 看样子应该是用不到,估计是多个驱动芯片才会用到。

SYNC:如果使用主机模式命令,同步信号将从 SYNC 引脚输出。 如果使用从机模式指令,同步信号将从 SYNC 引脚输入。(应该也用不到)

R_EXT:外部电阻连接输入引脚。连接一个外部电阻以设置输出端口的电流大小。所以这个角可以根据LED调整电流。

SCL/SCK:串行时钟输入引脚。I 2 C 接口的串行时钟 (SCL) 输入。 SPI 3 线接口的串行时钟 (CLK) 输入。

二、驱动

单字节数据(模拟SPI)

数据手册描述:

HT16D35A 芯片具有一个 SPI 3 线串行接口。
CSB 引脚用于识别传输的数据。传输是由有效的低电平信号 CSB 来控制的。当 CSB
降到低电平以后,数据才可以进行传输。
数据是从每个字节的 MSB 开始传输 – MSB 优先 数据会在 CLK 的上升沿被移入到寄存
器。
CSB 信号的下降沿处开始,输入数据的每 8 位依序自动加载到一个寄存器。
对于读模式,当 CSB 为低时,在发送完一个读命令代码后 DIO 引脚变为输出模式并开
始读取起始地址的设置值。在接收完输出数据后,如果 MCU CSB 信号设为高电平,
DIO 引脚将变为输入模式,并终止读模式周期。
对于读模式,数据将在 CLK 的下降沿输出到 DIO 引脚。

下面是写时序

根据时序从大的出发,1个字节是8位,所以传输一个字节只需要将CSB先拉低再拉高。下面是这部分的伪代码。如下图:

void Send_Byte(unsigned char a)
{
    Low CSB;        // 拉低CSB
    //发送

     High CSB;       // 拉高CSB
}

接下来就是1位的发送:一个字节有8位,以BIT7为例,传输一位时钟是先拉低,传输,最后再拉高。所以传输一位的伪代码:

void Send_Bit(void)
{
    clk_low;
    if(bit & 0x80)    io_high; // 高位传输
    else              io_low;  // 低位传输
    bit <<= 1;
    // 延时,等待完成以为
    clk_high;
    // 延时
}

那么发送一个字节的逻辑就有了,伪代码为:

void Send_Bit(type bit)
{
    for(int i = 8; i >0; i--)
    {
        clk_low;    //  时钟拉低
        
        // 高位传输
        if(bit & 0x80)    io_high; // 端口拉高
        else              io_low;  // 低位拉低
        bit <<= 1;   // 左移一位
        delay();
        clk_high;    // 时钟拉高
        delay();     // 延时
    }
}

-----------------
// 发送模块

CSB_LOW;
    
Send_Bit(0x..);    // 发送第一个指令
Send_Bit(0x..);    // 发送第二个指令
........

CSB_HIGH;

备注:这个只是单16位数据,连续十六位数据是。

三、指令

在HT16D35A手册中有命令描述,以及下面对应的解释

1、点亮第一个数码管

比如把第一个数码管全部点亮,那么需要配置ROM和COM即可

COM脚之前连接的是数码管的七段,所以必须全部输出开启。这两行的意思是先发送0x41h进入COM引脚控制,然后接着发送下一个指令。

CSB_LOW;
Send_Bit(0x41);    // 发送第一个指令
Send_Bit(0xFF);    // 发送第二个指令
CSB_HIGH;

CSB_LOW;
Send_Bit(0x42);  // 命令
Send_Bit(0x00);  // R27-R20,用不到
Send_Bit(0x00);  // R19-R12,用不到
Send_Bit(0x00);  // R11-R4,用不到
Send_Bit(0x01);  // 打开第一个数码管公共端  
CSB_HIGH;

2、别忘了端口配置,要不然点不亮

  • 12
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,针对你的问题,SPI(Serial Peripheral Interface)是一种串行通信接口,常用于单片机控制外部器件。而数码管可以通过SPI总线来驱动显示。下面是一个简单的SPI驱动数码管的示例代码: ```c #include <avr/io.h> #include <util/delay.h> #define SS_PIN PB2 #define MOSI_PIN PB3 #define SCK_PIN PB5 void spi_init() { DDRB |= (1 << SS_PIN) | (1 << MOSI_PIN) | (1 << SCK_PIN); SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR0); // enable SPI, set as master, set prescaler to 16 } void spi_write(uint8_t data) { SPDR = data; while (!(SPSR & (1 << SPIF))); // wait for transmission to complete } void display_number(uint8_t num) { uint8_t digits[4] = {0}; digits[0] = num % 10; digits[1] = (num / 10) % 10; digits[2] = (num / 100) % 10; digits[3] = (num / 1000) % 10; for (int i = 0; i < 4; i++) { PORTB &= ~(1 << SS_PIN); // select the display spi_write(1 << i); // set the digit position spi_write(digits[3 - i]); // send the digit value PORTB |= (1 << SS_PIN); // deselect the display _delay_ms(1); // delay to avoid ghosting } } int main() { spi_init(); while (1) { for (uint8_t i = 0; i < 10000; i++) { display_number(i); _delay_ms(10); } } return 0; } ``` 在这个示例代码中,我们使用AVR微控制器的SPI接口驱动了一个四位数码管。首先,我们需要初始化SPI总线,然后定义一个`display_number`函数用于显示一个数字。在`display_number`函数中,我们将输入的数字拆分成四个位,然后依次将每个位的值通过SPI接口发送给数码管。在主函数中,我们通过循环调用`display_number`函数来显示数字。需要注意的是,由于数码管的刷新速度较慢,所以我们需要在发送完每个数字后加上适当的延时,以避免出现“幽灵”数字。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值