【问题标题】:I am only able to control the first out of four 8x8 led matrices powered by Max7219我只能控制由 Max7219 驱动的四个 8x8 LED 矩阵中的第一个
【发布时间】:2021-12-27 15:40:58
【问题描述】:

我有 4 个串行连接的 8x8 LED 矩阵,我使用 SPI 协议进行通信。

在重写了几个库(python implementationrust implementationc implementation)之后, 因为它在我的系统上不起作用,而且我的代码至少可以工作一点,所以我只能控制四个连接的显示器中的第一个。

这是我在第一个显示器上显示目标图像的代码:

矩阵对象:

#![allow(dead_code)]
use spidev::Spidev;
use std::io::prelude::*;

// Maximum number of displays connected in series supported
const MAX_DISPLAYS: u8 = 8;

// Digits per addr
const MAX_DIGITS: u8 = 8;

// Possible command register values on the addr chip.
#[derive(Clone, Copy)]
pub enum Command {
    Noop = 0x00,
    Digit0 = 0x01,
    Digit1 = 0x02,
    Digit2 = 0x03,
    Digit3 = 0x04,
    Digit4 = 0x05,
    Digit5 = 0x06,
    Digit6 = 0x07,
    Digit7 = 0x08,
    DecodeMode = 0x09,
    Intensity = 0x0A,
    ScanLimit = 0x0B,
    Power = 0x0C,
    DisplayTest = 0x0F,
}

pub struct Matrix {
    pub spi: Spidev,
    pub devices: u8,
}
impl Matrix {
    pub fn init(&mut self) -> std::io::Result<()> {
        for device in 0..self.devices {
            self.send_bytes([device, Command::ScanLimit as u8, 0x07])?; // to scan for 8 digits or in this case columns
            self.send_bytes([device, Command::DecodeMode as u8, 0x00])?; // No Decode Mode for matrix
            self.send_bytes([device, Command::DisplayTest as u8, 0x00])?; // no displaytest desired
            self.send_bytes([device, Command::Power as u8, 0x01])?; // powers on the display
        }

        Ok(())
    }
    pub fn power_off(&mut self) -> std::io::Result<()> {
        for addr in 0..self.devices {
            self.send_bytes([addr, Command::Power as u8, 0x00])?;
        }
        Ok(())
    }
    pub fn send_command(&mut self, addr: u8, command: Command, value: u8) -> std::io::Result<()> {
        self.send_bytes([addr, command as u8, value])?;
        Ok(())
    }
    pub fn draw_raw(&mut self, addr: u8, data: [u8; 8]) -> std::io::Result<()> {
        let mut digit: u8 = 1; // column
        for b in data {
            self.send_bytes([addr, digit, b])?;
            digit += 1;
        }
        Ok(())
    }
    pub fn clear_display(&mut self, addr: u8) -> std::io::Result<()> {
        for col in 1..=MAX_DIGITS {
            self.send_bytes([addr, col, 0x00])?;
        }
        Ok(())
    }

    /// range 0 to 15
    pub fn set_intensity(&mut self, addr: u8, intesity: u8) -> std::io::Result<()> {
        self.send_bytes([addr, Command::Intensity as u8, intesity])?;
        Ok(())
    }

    fn send_bytes(&mut self, bytes: [u8; 3]) -> std::io::Result<()> {
        self.spi.write(&bytes)?;
        Ok(())
    }
}

main.rs

use spidev::{Spidev, SpidevOptions, SpiModeFlags};
use std::thread::sleep;
use std::time::Duration;

mod matrix;
use matrix::*;

fn create_spi() -> std::io::Result<Spidev> {
    let mut spi = Spidev::open("/dev/spidev0.0")?;
    let options = SpidevOptions::new()
         .bits_per_word(8)
         .max_speed_hz(20_000)
         .mode(SpiModeFlags::SPI_MODE_0)
         .build();
    spi.configure(&options)?;
    Ok(spi)
}

fn main() {
    println!("running");

    let spi = create_spi().unwrap();
    let mut matrix = Matrix{
        spi,
        devices: 4,
    };

    matrix.init().unwrap();

    matrix.draw_raw(0x01,
        [
            0b11111111,
            0b10000001,
            0b10000001,
            0b10011001,
            0b10011001,
            0b10000001,
            0b10000001,
            0b11111111
        ])
        .unwrap();

    sleep(Duration::from_secs(3));
    matrix.power_off().unwrap();
}

只看第一个显示一切正常,但这些都是问题:

  • 在第二个显示器上,每个像素都被点亮
  • 第三个显示屏完全不亮,正如预期的那样
  • “位图”在显示器 1 和 4 上绘制

我认为问题在于我如何通过 SPI 发送数据,但我不确定。

我需要做什么才能让它工作?

【问题讨论】:

  • 这个问题和your previous question有什么不同?
  • @the busybee 我只是想总结一下我的问题,因为我的旧问题中有部分,我已经解决了,我不想删除它,因为它可能对其他人有帮助。
  • 因此您可以将其标记为已解决,或者至少对其进行编辑并参考此问题以了解仍然缺少的部分。
  • 不要做这个浪费时间的任务,而是在内核中编写一个驱动程序(在 drivers/auxdisplay 下),然后开心!

标签: rust driver microcontroller


【解决方案1】:

我现在放弃了使用 SPI 的想法,并从 library 复制了该方法

矩阵对象现在看起来像这样:

use gpio_cdev::{LineHandle, Error};

// Maximum number of displays connected in series supported
const MAX_DISPLAYS: u8 = 8;

// Digits per addr
const MAX_DIGITS: u8 = 8;

// Possible command register values on the addr chip.
#[derive(Clone, Copy)]
pub enum Command {
    Noop = 0x00,
    Digit0 = 0x01,
    Digit1 = 0x02,
    Digit2 = 0x03,
    Digit3 = 0x04,
    Digit4 = 0x05,
    Digit5 = 0x06,
    Digit6 = 0x07,
    Digit7 = 0x08,
    DecodeMode = 0x09,
    Intensity = 0x0A,
    ScanLimit = 0x0B,
    Power = 0x0C,
    DisplayTest = 0x0F,
}

pub struct Matrix {
    pub cs: LineHandle,
    pub data: LineHandle,
    pub clock: LineHandle,
    pub devices: u8,
    pub buffer: [u8; MAX_DISPLAYS as usize * 2]
}
impl Matrix {
    pub fn new(
        cs: LineHandle,
        data: LineHandle,
        clock: LineHandle,
        devices: u8,
    ) -> Self {
        Matrix { cs, data, clock, devices, buffer: [0; MAX_DISPLAYS as usize * 2] }
    }

    pub fn init(&mut self) -> Result<(), Error> {
        for device in 0..self.devices {
            self.write_raw(device, Command::ScanLimit as u8, 0x07)?; // to scan for 8 digits or in this case columns
            self.write_raw(device, Command::DecodeMode as u8, 0x00)?; // No Decode Mode for matrix
            self.write_raw(device, Command::DisplayTest as u8, 0x00)?;
            self.write_raw(device, Command::Power as u8, 0x01)?; // powers on display
        }

        Ok(())
    }
    pub fn power_off(&mut self) -> Result<(), Error>  {
        for addr in 0..self.devices {
            self.write_raw(addr, Command::Power as u8, 0x00)?;
        }
        Ok(())
    }
    pub fn send_command(&mut self, addr: u8, command: Command, value: u8) -> Result<(), Error> {
        self.write_raw(addr, command as u8, value)?;
        Ok(())
    }
    pub fn draw_raw(&mut self, addr: u8, data: [u8; 8]) -> Result<(), Error> {
        let mut digit: u8 = 1; // column
        for b in data {
            self.write_raw(addr, digit, b)?;
            digit += 1;
        }
        Ok(())
    }

    pub fn clear_display(&mut self, addr: u8) -> Result<(), Error> {
        for col in 1..=MAX_DIGITS {
            self.write_raw(addr, col, 0x00)?;
        }
        Ok(())
    }

    /// range 0 to 15
    pub fn set_intensity(&mut self, addr: u8, intesity: u8) -> Result<(), Error> {
        self.write_raw(addr, Command::Intensity as u8, intesity)?;
        Ok(())
    }

    // new method that replaces SPI
    fn write_raw(&mut self, addr: u8, header: u8, data: u8) -> Result<(), Error> {
        let offset = addr as usize * 2;
        let max_bytes = self.devices * 2;
        self.buffer = [0; MAX_DISPLAYS as usize * 2];

        self.buffer[offset] = header;
        self.buffer[offset + 1] = data;

        self.cs.set_value(0)?;
        for b in 0..max_bytes as usize {
            let value = self.buffer[b];

            for i in 0..8 {
                if value & (1 << (7 - i)) > 0 {
                    self.data.set_value(1)?;
                } else {
                    self.data.set_value(0)?;
                }

                self.clock.set_value(1)?;
                self.clock.set_value(0)?;
            }
        }
        self.cs.set_value(1)?;

        Ok(())
    }
}

我可以像这样使用gpio-cdev 访问 GPIO 引脚:

use gpio_cdev::{Chip, LineRequestFlags, LineHandle, Error};

fn get_pins(cs: u32, data: u32, clock: u32) -> Result<(LineHandle, LineHandle, LineHandle), Error> {
    let mut chip = Chip::new("/dev/gpiochip0")?;
    
    let cs = chip
        .get_line(cs)? // 24 8
        .request(LineRequestFlags::OUTPUT, 0, "chip-select")?;

    let data = chip
        .get_line(data)? // 19 10
        .request(LineRequestFlags::OUTPUT, 0, "mosi")?;

    let clock = chip
        .get_line(clock)? // 23 11
        .request(LineRequestFlags::OUTPUT, 0, "clock")?;

    Ok( (cs, data, clock) )
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多