STM32MP157 | 基于 Linux SPI 驱动M74HC595数码管显示

本文详细介绍了M74HC595移位寄存器的工作原理及在STM32MP151开发板上的设备树配置过程,包括设置SPI引脚、控制器节点以及编写设备树节点。接着,展示了如何编写Linux内核的SPI设备驱动,包括初始化、设备注册和卸载。最后,实现了字符设备驱动,包含了打开、关闭和ioctl接口,并提供了测试驱动的简单应用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、M74HC595简介

M74HC595器件是采用硅栅C2MOS技术制作的具有输出锁存器(3态)的高速CMOS 8位移寄存器。

该设备包含一个8位串行进、并行出移位寄存器,它提供一个8位d型存储寄存器。存储寄存器有8个3状态输出。为移位寄存器和存储寄存器都提供了单独的时钟。

移位寄存器有直接覆盖清除,串行输入和串行输出(标准)引脚级联。移位寄存器和存储寄存器都使用正边缘触发时钟。如果两个时钟连接在一起,移位寄存器状态将始终是存储寄存器前面的一个时钟脉冲。

特性:

  • 高速:在Vcc = 6V时,fMAx = 59mhz(典型)
  • 低功耗:Icc = 4 μA (max)
  • 工作电压范围宽:Vcc (opr.) = 2 V至6 V

1.M74HC595设备操作原理图:

在这里插入图片描述

2. 开发板原理图

在这里插入图片描述

在这里插入图片描述

二、 添加设备树的节点

1.设置引脚

首先设置spi引脚的复用功能,找到 spi4_pins_b 节点:

vi stm32mp15-pinctrl.dtsi

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tndfKFsg-1662622887640)(图片/1662616736518.png)]

2. 找出控制器的设备树

stm32mp151.dtsi

spi4: spi@44005000 {
   
    #address-cells = <1>; 
    #size-cells = <0>; 
    compatible = "st,stm32h7-spi";                                                         
    reg = <0x44005000 0x400>;
    interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&rcc SPI4_K>;
    resets = <&rcc SPI4_R>;
    dmas = <&dmamux1 83 0x400 0x01>,
           <&dmamux1 84 0x400 0x01>;
    dma-names = "rx", "tx";
    power-domains = <&pd_core>;
    status = "disabled";
};

3. 根据内核帮助文档编写自己的设备树

/home/linux/linux-5.10.61/Documentation/devicetree/bindings/i2c/

&spi4{
   
    pinctrl-names = "default", "sleep";
    pinctrl-0 = <&spi4_pins_b>;
    pinctrl-1 = <&spi4_sleep_pins_b>;
    cs-gpios = <&gpioe 11 0>;
    status = "okay";
    
    m74hc595@0{
   
        compatible = "m74hc595";
        reg = <0>;
        spi-max-frequency = <10000000>; //10Mhz
    };
};

4. 重新编译设备树

make dtbs

重启开发板

安装驱动

三. 编写M74HC595设备驱动

1.先搭个spi设备驱动框架

#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>

int m74hc595_probe(struct spi_device *spi)
{
   
    printk("%s:%d\n", __func__, __LINE__);
    return 0;
}
int m74hc595_remove(struct spi_device *spi)
{
   
    printk("%s:%d\n", __func__, __LINE__);
    return 0;
}

struct of_device_id oftable[] = {
   
    {
   .c
stm32版八位串行595数码管 #include "sys.h" //点击魔术棒加入对应的文件夹地址,FWLIB里加入相应的头文件 #include "delay.h" #include "usart.h" #include "led.h" #include "key.h" //////////////////////////////////////////////////////////////////////////// unsigned char fseg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; unsigned char segbit[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; unsigned char disbuf[8]={0,0,0,0,0,0,0,0}; #define uchar unsigned char #define DIO LED0//串行数据输入 #define RCLK LED1 //时钟脉冲信号——上升沿有效 #define SCLK LED2//打入信号————上升沿有效 void LED4_Display (void); // LED显示 void LED_OUT(uchar X); // LED单字节串行移位函数 void data_OUT(int data); unsigned char LED_0F[]; // LED字模表 //----------------------------------------------------------------------------- // 全局变量 uchar LED[8]; //用于LED的8位显示缓存 /////////////////////////////////////////////////////////////////////////////////// int main(void) { u8 t=0; delay_init(); //延时函数初始化 NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 uart_init(9600); //串口初始化为9600 LED_Init(); KEY_Init(); ////////////////////////////////////////////////////////// // LED[0]=0; // LED[1]=2; // LED[2]=3; // LED[3]=4; // LED[4]=5; // LED[5]=6; // LED[6]=7; // LED[7]=8; ///////////////////////////////////////////////////////////////// while(1) { LED4_Display ();//串口数码管 data_OUT(123456); // printf("love"); } } ///////////////////////////////////////////////////////////////// void LED4_Display (void) { unsigned char *led_table; // 查表指针 uchar i; //显示第1位 led_table = LED_0F + LED[0]; i = *led_table; LED_OUT(i); LED_OUT(0x01); RCLK = 0; RCLK = 1; //显示第2位 led_table = LED_0F + LED[1]; i = *led_table; LED_OUT(i); LED_OUT(0x02); RCLK = 0; RCLK = 1; //显示第3位 led_table = LED_0F + LED[2]; i = *led_table; LED_OUT(i); LED_OUT(0x04); RCLK = 0; RCLK = 1; //显示第4位 led_table = LED_0F + LED[3]; i = *led_table; LED_OUT(i); LED_OUT(0x08); RCLK = 0; RCLK = 1; //显示第5位 led_table = LED_0F + LED[4]; i = *led_table; LED_OUT(i); LED_OUT(0x10); RCLK = 0; RCLK = 1; //显示第6位 led_table = LED_0F + LED[5]; i = *led_table; LED_OUT(i); LED_OUT(0x20); RCLK = 0; RCLK = 1; //显示第7位 led_table = LED_0F + LED[6]; i = *led_table; LED_OUT(i); LED_OUT(0x40); RCLK = 0; RCLK = 1; //显示第8位 led_table = LED_0F + LED[7]; i = *led_table; LED_OUT(i); LED_OUT(0x80); RCLK = 0; RCLK = 1; } void LED_OUT(uchar X) { uchar i; for(i=8;i>=1;i--) { if (X&amp;0x80) DIO=1; else DIO=0; X<<=1; SCLK = 0; SCLK = 1; } } void data_OUT(int data) { LED[7] = 0; LED[6] = 0; LED[5] = data % 1000000 / 100000; LED[4] = data % 100000 / 10000; // LED[3] = data % 10000 / 1000; LED[2] = data % 1000 / 100; LED[1] = data % 100 / 10; LED[0] = data % 10; } unsigned char LED_0F[] = {// 0 1 2 3 4 5 6 7 8 9 A b C d E F - 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x8C,0xBF,0xC6,0xA1,0x86,0xFF,0xbf }; ///////////////////////////////////////////////////////////////////////////////////////////////
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值