电子头条

Verilog自学(7) 用SPI控制GPIO输出状态

2022-04-17
    阅读数:
//如果是写入8bit的话,最高位就是8'h80 //如果是写入16bit的话,最高位是16'h8000//多少bit 直接改spi_bit 即可`define spi_highest_bits 16'h8000`define spi_bit 16module SPI(    input [`spi_bit-1:0]Data,    //定义SPI 8位写入数据    input  sysclk,    //定义系统输入时钟    input miso,    // 定义SPI 输入引脚    output reg mosi,    output reg cs,    output reg sclk    // 定义SPI 输出引脚);reg [1:0]SateConter = 0 ;reg [7:0]DataSendCounter;    // 定义计数状态initial begin    mosi<=1'b0;    cs<=1'b1;    sclk<=1'b1;    DataSendCounter<=4'b0000;end//初始化GPIOalways@(posedge sysclk) begin     SateConter=SateConter+1;    //当到达计数值以后拉高Cs    cs=(DataSendCounter<(`spi_bit+1)?1'b0:1'b1);    if(SateConter==1)    sclk<=1'b0;//第一个计数状态拉低SCLK     else if(SateConter==2)    //第二个状态写入数据    begin        if (((Data<<DataSendCounter)&`spi_highest_bits)==`spi_highest_bits) begin            mosi<=1'b1;             end        else begin            mosi<=1'b0;        end        //每次写入后计数+1        DataSendCounter<=DataSendCounter+1'b1;    end    else if(SateConter>2)    //第三个计数状态拉高SCLK 计数值清0    begin        sclk<=1'b1;        SateConter=0;    endendendmodule

因为是各种模块组合起来,所以和之前的会有重合

//使用define 重定义memory 变量 //看起来更加直观 `符号 在键盘~的位置 ESC下方  //定义最大输入字节 
//使用时候修改 spi_bit 和reg_restValue 定义就行`define spi_bit 16`define reg_restValue 16'h0000module spi_reg( //定义外部SCLK输入 input sclk, //定义MISO输入 input miso, //定义器件SPI使能 input nss, //定义时钟 input clk, //定义复位 input rst, //定义 寄存器输出 output reg [`spi_bit-1:0] reg_data);//定义缓存器reg [`spi_bit-1:0] reg_data_temp;//定义SPI接收计数器reg [3:0] spi_rx_counter;initial begin reg_data<=`reg_restValue; reg_data_temp<=`reg_restValue; spi_rx_counter<=4'b0000;endalways @(posedge sclk or nss) begin //如果nss为高 将缓存器最终输出给reg_data if (nss) begin reg_data<=reg_data_temp; //清零接收计数器 spi_rx_counter<=4'b0000; end else begin //reg_data_temp每次都移位一格 reg_data_temp<=reg_data_temp<<1'b1; reg_data_temp[0]<=miso; //计数发送到第几个字节 spi_rx_counter<=spi_rx_counter+1'b1; //当收完地址位之后 将数据更新 否则等于其自身 reg_data[`spi_bit-1:`spi_bit-8]<=(spi_rx_counter==9?reg_data_temp[7:0]:reg_data[`spi_bit-1:`spi_bit-8]); end
end
endmodule

// 程序功能://  通过SPI 写入寄存器地址 改变寄存器输出//定义GPIO寄存器位置`define gpioa_addr   8'h01 `define gpiob_addr   8'h02`define gpioc_addr   8'h03`define gpioOn_addr  8'h08module prj(  //定义外部SCLK输入  input sclk,  //定义MISO输入  input miso,  //定义器件SPI使能  input nss,  //定义时钟  input clk,  //定义复位  input rst,  //定义 寄存器输出  output reg [7:0] gpioa,  output reg [7:0] gpiob,  output reg [7:0] gpioc);//定义临时寄存器wire[15:0] reg_temp;//当reg_temp发生改变 查询地址always @(reg_temp) begin  //判断reg_temp[15:8]对应那个地址  case (reg_temp[15:8])    `gpioa_addr :begin      //将地址对应的寄存器赋值      gpioa<=reg_temp[7:0];      end    `gpiob_addr :begin      gpioa<=reg_temp[7:0];      end    `gpioc_addr :begin      gpioa<=reg_temp[7:0];      end    `gpioOn_addr :begin      gpioa<=8'hAA;      end    default :begin      gpioa<=8'h00;      gpiob<=8'h00;      gpioc<=8'h00;    end        endcaseend

//调用spi_reg 来写入数据spi_reg U13( .sclk(sclk), .miso(miso), .nss(nss), .clk(clk), .rst(rst), .reg_data(reg_temp));
endmodule

`timescale 1ns/1psmodule spi_reg_Tb;reg CLK; reg RST;

// spi
wire SCLK; wire MISO;wire NSS; wire MOSI;wire [7:0]GPIOA;wire [7:0]GPIOB;wire [7:0]GPIOC;reg [1:0]SclkCounter;always #20 CLK=~CLK;initial begin CLK=1'b0; RST<=1'B1;// SCLK<=1'b0;// MISO<=1'B0;// NSS<=1'B1;
endSPI U2( .Data(16'h08aa), //定义SPI 8位写入数据 .sysclk(CLK), //定义系统输入时钟 .miso(MISO), // 定义SPI 输入引脚 .mosi(MOSI), .cs(NSS), .sclk(SCLK) // 定义SPI 输出引脚);prj GPIO_OUT( .sclk(SCLK), .miso(MOSI), .nss(NSS), .clk(CLK), .rst(RST), .gpioa(GPIOA), .gpiob(GPIOB), .gpioc(GPIOC));
endmodule

VS Code 纯净版

简单验证如下????


展开↓