【问题标题】:SPI initializing in Atmel studioAtmel 工作室中的 SPI 初始化
【发布时间】:2018-09-22 12:14:23
【问题描述】:

我正在尝试使用我的 Micro OLED Sparkfun 显示器(这是数据表 enter link description here),但我遇到了代码问题。也许是代码中的问题,因为我第一次在 Atmel 使用 SPI,所以如果有人这么好,请检查一下,给我一些建议,我会非常感激。

编辑:这是显示线的更改代码和图片

#define F_CPU 16000000
 #include <avr/io.h>
 #include <util/delay.h>
 #define SCK DDB5
 #define SDIN DDB3
 #define D_C DDB0
 #define CS DDB2
 #define RST DDB1

 void SPI_MasterInit(void)
 {
     /* Set MOSI and SCK output, all others input */
     DDRB = (1<<SCK)|(1<<SDIN)|(1<<D_C)|(1<<CS)|(1<<RST);
     /* Enable SPI, Master, set clock rate fck/16 */
     PORTB |= (1<<CS);
     PORTB |= (1<<D_C);
     SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(0<<DORD);
 }
 void SPI_MasterTransmit_Command(int cCommand)
 {
     PORTB &= ~(1<<CS);
     PORTB &= ~(1<<D_C);
     _delay_ms(200);
     /* Start transmission */
     SPDR = cCommand;
     /* set dc and cs low to send command */
     /* Wait for transmission complete */
     while(!(SPSR & (1<<SPIF)));
     /* set dc cs high again */
     PORTB |= (1<<CS);
     PORTB |= (1<<D_C);


 }

 void Display_ON(void)
 {
     PORTB &= ~(1<<RST);
     _delay_ms(50);
     PORTB |= (1<<RST);
     _delay_ms(50);
     PORTB &= ~(1<<RST);
     _delay_ms(50);
     SPI_MasterTransmit_Command(0xAF);
     _delay_ms(200);
 }

 int main(void)
 {
     SPI_MasterInit();
     Display_ON();
     SPI_MasterTransmit_Command(0xA5);

 }

【问题讨论】:

  • 显示控制器如何与板子连接?什么是PB0? PB1? CS# 在哪里连接以及在哪里控制?您的代码中没有在命令之前拉下某些东西并在之后将其拉起的地方。
  • 我建议您在断言片选之前更改 C/D。不要认为这是你的问题,但你不想在那里比赛。
  • 如果您在芯片中使用 spi 外设,最好有一个示波器。它们现在便宜得多,大约 250 美元,您可以获得一个非常适合此应用程序的 4 通道。如果没有得到一些 LED 将它们放在 MCU 的输出上,请尝试尽可能慢地为 MCU 计时,看看您是否可以直观地看到 LED 上的状态变化。如果没有得到另一个单片机并用它来轮询线路,把它变成一个逻辑分析仪。假设芯片供应商的文档有问题,即使文档中只有一个错误,它也可能出现在您正在处理的外围设备中......
  • 忽略“模式”数字查看从机的数据表,在示波器或逻辑分析仪上确保数据在正确的半时钟边​​沿上更改状态,以便从机在正确的时钟边沿上对其进行采样时钟边沿。反之亦然,尽管使用这样的显示,您通常不需要回读任何内容。
  • 移除第二个 PORTB &= ~(1Display_ON(),否则显示将保持在重置状态

标签: c arduino avr spi atmel


【解决方案1】:

首先。当您在主模式下使用 AVR ATmega 上的 SPI 时,SS 引脚虽然不被 SPI 模块直接使用,但应该始终 配置为输出,否则引脚上的高电平会将 SPI 模块切换到从模式。换句话说,如果您使用例如 ATmega328(P),则应将 PB2 配置为输出(应设置 DDRB 中的 DD2 位)。最好将 SSD1306 的 CS# 连接到此引脚。

第二。 连接 SSD1306 时,应连接 4 条线(参见datasheet 的第 17 页): 1) SCLK - 串行时钟 - 将其连接到 SPI 端口的 SCK 引脚(例如,用于 ATmega328 的 PB5) 2)SDAT - 串行数据 - 将其连接到 MOSI 引脚(PB3) 3) CS# - 片选 - 将其连接到 SS 引脚 (PB2) 4) D/#C - 数据/命令选择 - 将其连接到任何空闲引脚(我想您已将其连接到 PB0) 模块也可能有RESET输入,我想你已经把它连接到PB1了。

因此,向 SSD1306 发送数据或命令字节应如下所示:

PORTB &= ~(1 << CS); // pulling the CS# line low
PORTB |= (1 << D_C); // high for DATA
or
PORTB &= ~(1 << D_C); // low for COMMAND
SPDR = cData; // transmit the byte
while(!(SPSR & (1<<SPIF))) {} // wait the transmission to complete
PORTB |= (1 << CS); // pull the CS# line back high

CS# 可以通过几个命令保持在低电平,而不会上升。它有助于确定命令的边缘。

第三。 命令 0xAF 将打开显示器,但它可能不会显示任何内容,因为其中没有数据,因此您可能看不到任何区别。 尝试在此之后发送命令 0xA5,它将点亮所有像素 - 仅用于测试目的。

UPD 此外,您还必须打开 DC-DC 电荷泵(参见应用说明,第 62 页,datasheet 末尾)。它由两个命令字节 0x8D 0x14 的序列完成。在打开显示器之前(即在 0xAF 之前)发送它

【讨论】:

    【解决方案2】:

    很遗憾,您没有具体说明您正在使用的 µC。我只是使用 ATMEGA32 作为参考。希望您的 AVR 具有相同的配置。

    ATMEGA32 在端口 B 上也有一个 SPI 接口。您依赖 DDRB 寄存器的复位值(为零)。为您的引脚配置显式设置所有所需的值会很好。从 ATMEGA 的数据表来看,您似乎没有正确初始化引脚。只需将 SPI 接口的 PB7 和 PB5 设置为输出即可。在您的初始化中,您将 PB4、PB6 和 PB7 设置为输出。你混合了 MISO 和 MOSI。

    这里是我的初始化例程:

    /* 
    SPI pin configuration:
    PB7: SCK         Output
    PB6: MISO        Input
    PB5: MOSI        Output
    PB4: Chip select Output
    */
    void SPI_MasterInit(void){
      DDRB = 0x00;
      DDRB |= ((1 << DDB2) | (1 << DDB5) | (1 << DDB7));
      PORTB |= (1<<PB2);
      /* Enable SPI, Master, set clock rate fck/16 */
      SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
    }
    

    您还需要检查以下内容:

    • 显示器是否支持您选择的 SPI 频率?
    • IDLE 期间 SCK 的状态应该是什么?
    • 应该何时对 SPI 数据进行采样?在 SCK 的上升沿或下降沿期间。
    • CS 是否按照 OLED 显示器数据表中的时序图设置?

    如果您处理了所有这些事情,请回来提供简短的反馈。我希望这个答案能给你一些指导方针。

    【讨论】:

    • 嗨,我用的是atmega328p,我对代码做了一些小升级,但是突然显示仍然不想工作pastebin.com/zG3JpwWv
    • 在您的新代码中,您将SDIN 设置为输出(应该是输入),并在初始化后拉动CSdown,这是您不应该这样做的。 CS 上的低电平激活显示器的 SPI 接口。如果你想开始通信,你应该只将它设置为低,例如当您开始传输数据时。仅将其配置为输出。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-06
    • 1970-01-01
    相关资源
    最近更新 更多