基于 ZYNQ ECO开发板和STM32F103C8T6的遥控小车

目录

预计效果:

材料清单:

  程序编写:

        配置ZYNQ ECO开发板

                1. 串口接收模块

                2. LED模块

                3. 电机驱动模块

                4. 速度控制模块

                5. 超声波模块

                6. 循迹模块

                7. 主程序

                        引脚配置

                        模块引入

                        模式判断

                 LED控制

                        PWM调速

                        方向控制

                car_kz(最终程序)

        STM32F103C8T6遥控器

                1. 4*4按键矩阵

2. 主程序


预计效果:

                计划使用4x4按键矩阵来控制遥控车,并且希望实现以下功能:可调速、控制模式(循迹、避障、遥控)、OLED显示当前模式、按键状态、速度和运动姿态。

以下是对您的计划的详细说明:

  1. 按键输入:使用4x4按键矩阵进行按键输入。按键矩阵可以将多个按键连接到少量的引脚上。可以通过扫描按键矩阵来检测哪个按键被按下,并获取相应的按键状态。

  2. 调速功能:使用可调速的驱动器或控制器来控制遥控车的速度。根据按键输入或其他输入信号,调整驱动器的输出来控制车辆的速度。

  3. 控制模式:使用按键输入来切换遥控车的控制模式。可以定义不同的控制模式,如循迹、避障和遥控。根据按键输入的模式选择,切换遥控车的行为。

  4. OLED显示:使用OLED显示屏来显示当前的控制模式、按键状态、速度和运动姿态等信息。可以使用合适的库或驱动程序来控制OLED显示屏,并将相关信息显示在屏幕上。

        使用4x4按键矩阵来控制遥控车,并实现可调速、控制模式切换和信息显示等功能。

材料清单:

  1. ZYNQ ECO开发板(用于遥控车控制)
  2. STM32F103C8T6微控制器(用于遥控器)
  3. 4x4矩阵按键(用于遥控器输入)
  4. N20电机(数量:4)
  5. 麦克纳姆轮(数量:4)
  6. HC14蓝牙模块(用于无线通信)
  7. 0.96寸OLED显示屏(用于显示车辆状态)
  8. HC-SR04超声波测距模块(用于距离测量)
  9. TCRT5000循迹模块(数量:2,用于循迹功能)
  10. TB6612FNG电机驱动(数量:2)
  11. 12V电池
  12. 智能小车电源模块DC-DC 12V转5V 3.3V

  程序编写:

        配置ZYNQ ECO开发板

                1. 串口接收模块

`timescale 1ns / 1ps
    module rx_dat(
    input           clk         ,
    input           rst_n       ,
    input           rx          ,
    output          rx_done     ,
    output [7:0]    rx_data
    );
    
parameter   HZ=50_000_000;
parameter   bps = 9600;
//parameter  HZ   =50_00;//1s时间
//parameter  bps  = 96      ;//波特率   
    
parameter  delay=HZ/bps     ;//传输一个bit需要的时间         
reg  [31:0]  cnt;           //时钟计数器
reg  [5:0 ]  cnt_bit;       //传输第几bit计数器
reg          en;            //使能
reg  [7:0 ]  data_reg;      //数据中间寄存
always  @(posedge clk)
    if(!rst_n)
        en<=0;
    else if(!rx)
        en<=1;
    else if(cnt==delay/2-1&&cnt_bit==9)
        en<=0;
    else
        en<=en;
always @(posedge clk)
    if(!rst_n)begin
        cnt<=0;
        cnt_bit<=0;
    end
    else if(en)begin
        if(cnt==delay-1)begin
            cnt<=0;;
            cnt_bit<=cnt_bit+1;
            end
        else    begin
            cnt<=cnt+1;
            cnt_bit<=cnt_bit;
        end         
    end
    else begin
        cnt<=0;
        cnt_bit<=0;
    end
always @(posedge clk)
    if(!rst_n)
        data_reg<=0;
    else if(cnt_bit>0&&cnt_bit<9&&cnt==delay/2-1)
        data_reg[cnt_bit-1]=rx;
    else
        data_reg<=data_reg;
        
assign  rx_data=(cnt_bit==9)?data_reg:rx_data;
assign  rx_done=(cnt_bit==9&&cnt==delay/2-1)?1:0;

endmodule

时钟输入clk、复位输入rst_n、接收数据输入rx、接收完成信号输出rx_done和接收数据输出rx_data

该模块的功能是接收串口数据,并将接收到的数据存储在rx_data中,同时产生rx_done信号表示数据接收完成。

  1. parameter行定义了两个参数:HZ表示时钟频率,bps表示波特率。
  2. delay是一个计算所需时间的参数,表示传输一个bit所需要的时钟周期数。
  3. cnt是一个32位的时钟计数器,用于计数时钟周期。
  4. cnt_bit是一个6位的计数器,用于计数传输的第几个bit。
  5. en是一个使能信号,用于控制数据接收的使能状态。
  6. data_reg是一个8位的寄存器,用于暂存接收到的数据。
  7. always @(posedge clk)语句表示在时钟上升沿触发的时候执行内部逻辑。
  8. 最后的assign语句用于将data_regrx_data连接起来,并将接收完成的条件赋值给rx_done

该模块的功能是在每个时钟周期中计数,根据时钟周期和波特率的关系来判断何时接收到一个完整的数据位,并将其存储在rx_data中。接收完成时,会产生rx_done信号。

请注意,该模块仅用于接收数据,还需要后面的模块来处理接收到的数据,

串口

                2. LED模块

`timescale 1ns / 1ps

module led_mk(
    input               clk         ,
    input               rst_n       ,
    input   [4:0]       led_zt      ,
    output  reg[3:0]    led
    );
    parameter led1 = 0;
    parameter led2 = 1;
    parameter led3 = 2;
    parameter led4 = 3;
    parameter led5 = 4;
    
    reg [3:0]   c_led;
    reg [3:0]   n_led;
    
    always @(posedge clk)
        if(!rst_n)
            c_led <= led1;
        else
            c_led <= n_led;
        
    always @(*)
        if(!rst_n)
            n_led = 0;
        else begin
            case(led_zt)
                led1: begin
                    n_led = led1;
                    end
                led2:begin
                     n_led = led2;
                    end
                led3:begin
                     n_led = led3;
                    end
                led4:begin
                     n_led = led4;
                    end
                led5:begin
                     n_led = led5;
                    end
                default:
                    n_led =  n_led;
              endcase
        end
                
       always @(posedge clk)
            if(!rst_n)
                led <= 0;
            else begin
                case(c_led)
                led1: begin
                        led <= 4'b0000;
                    end
                led2:begin
                        led <= 4'b0001;
                    end
                led3:begin
                        led <= 4'b0011;
                    end
                led4:begin
                        led <= 4'b0111;
                    end
                led5:begin
                        led <= 4'b1111;
                    end
                default:
                    led <= led;
                 endcase
            end
endmodule

一个简单的LED驱动模块,根据输入的led_zt选择不同的LED显示模式。

  1. module led_mk定义了模块名和输入输出端口。
  2. parameter行定义了LED的不同状态,通过数字编码来表示。
  3. reg行定义了两个寄存器c_ledn_led,用于存储当前和下一个LED状态。
  4. always @(posedge clk)表示在时钟上升沿触发的时候执行内部逻辑。
  5. if-else语句用于根据时钟和复位信号的状态更新c_led寄存器。
  6. always @(*)表示在输入信号变化时执行内部逻辑。
  7. case语句用于根据led_zt选择不同的LED状态,并将结果存储到n_led寄存器中。
  8. 另一个always @(posedge clk)块用于根据c_led的值来更新led输出。
  9. case语句提供了不同的LED状态对应的输出值。

该模块的功能是根据输入的led_zt选择不同的LED状态,并在时钟上升沿更新LED的输出值。此模块没有提供复杂的控制逻辑,只是简单地根据输入来选择LED的状态。

                3. 电机驱动模块

`timescale 1ns / 1ps

module DIRECTION(
        input           clk             ,
        input           rst_n           ,
        input    [4:0]  DIRECTION_zt    ,
        output reg[1:0]   left_whell     ,
        output reg[1:0]   right_whell    
    );
    //此处采用2为二进制控制  
    //       1       0
    //            10前进      01后退    00停止
    //      
    
    
    parameter   forward     = 0;
    parameter   retreat     = 1;
    parameter   turn_right  = 2;
    parameter   turn_left   = 3;
    parameter   stop        = 4;
    
    reg [3:0]   c_whell;
    reg [3:0]   n_whell;
    
    always @(posedge clk)
        if(!rst_n)
            c_whell <= stop;
        else
            c_whell <= n_whell;
        
    
    always @(*)
        if(!rst_n)
            n_whell = 0;
        else begin
            case(DIRECTION_zt)
                forward: begin
                    n_whell = forward;
                    end
                retreat:begin
                     n_whell = retreat;
                    end
                turn_right:begin
                     n_whell = turn_right;
                    end
                turn_left:begin
                     n_whell = turn_left;
                    end
                stop:begin
                     n_whell = stop;
                    end
                default:
                    n_whell =  stop;
              endcase
        end
                
       always @(posedge clk)
            if(!rst_n)  begin
                left_whell  <= 2'b00;
                right_whell <= 2'b00;
                end
            else begin
                case(c_whell)
                forward: begin
                        left_whell  <= 2'b10;
                        right_whell <= 2'b10;
                    end
                retreat:begin
                        left_whell  <= 2'b01;
                        right_whell <= 2'b01;
                    end
                turn_right:begin
                        left_whell  <= 2'b10;
                        right_whell <= 2'b01;
                    end
                turn_left:begin
                        left_whell  <= 2'b01;
                        right_whell <= 2'b10;
                    end
                stop:begin
                        left_whell  <= 2'b00;
                        right_whell <= 2'b00;
                    end
                default:begin
                        left_whell  <= 2'b00;
                        right_whell <= 2'b00;
                        end
                 endcase
            end
endmodule

DIRECTION模块通过根据输入的方向状态控制车辆的左右轮引脚电平,从而控制电机的转向。

  • 前进(0):左轮引脚为2'b10,右轮引脚为2'b10,让遥控车向前行驶。
  • 后退(1):左轮引脚为2'b01,右轮引脚为2'b01,让遥控车后退。
  • 左转(2):左轮引脚为2'b01,右轮引脚为2'b10,让遥控车向左转。
  • 右转(3):左轮引脚为2'b10,右轮引脚为2'b01,让遥控车向右转。
  • 停止(4):左轮引脚为2'b00,右轮引脚为2'b00,让遥控车停止。

                4. 速度控制模块

`timescale 1ns / 1ps
module SY6_PWM(
    input                           clk         ,
    input                           rst_n       ,
    input     [31:0]                 speed       ,    
    output                            left_pwm    ,
    output                            right_pwm
    );
 
    
    reg  [31:0]   i = 0;
    //parameter   delay=1;
    parameter   delay=50;
    reg [31:0]  cnt ;
    reg [31:0]  us  ;
    reg [31:0]  ms  ;
    
    

    //基础计数 先计数到50
    always @(posedge clk)
        if(!rst_n)
            cnt <=0;
        else if(cnt == delay -1)
            cnt<=0;
        else
            cnt<=cnt+1;
            
    
    always @(posedge clk)
        if(!rst_n)
            us <=0;
        else if(cnt == delay -1)begin
            if(us == 999)
                us <=0;
            else 
                us<=us+1;
            end
        else
            us<=us;
                        
    always @(posedge clk)
        if(!rst_n)begin
            ms <=0;
            end
        else if(cnt == delay -1 && us== 999)begin
            if(ms == 999)begin
                ms <=0;
                end
            else 
                ms<=ms+1;
            end
        else
            ms<=ms;
            

    assign  left_pwm  =(speed >= us ) ?1:0;     
  assign  right_pwm =(speed >= us) ?1:0;   
  
    
    /*
    always @(*)begin
        if(!rst_n)  begin
           led <= 0;
           //mode <= H;
           end
        else if(mode == H)
                led <= (ms>=us)?4'b0111:4'b0000;
        else if(mode == L )
                led <= (ms<=us)?4'b0111:4'b0000;
    end
    */
endmodule

输入的speed参数决定了PWM输出的占空比。当us计数小于等于speed时,left_pwmright_pwm输出高电平;否则输出低电平。需要注意的是,一旦speed参数被接收后,不能对其进行处理,否则PWM输出将一直为低电平。

该模块的功能是根据输入的speed参数控制左右PWM输出的占空比。通过调整speed参数的值可以控制PWM输出的高电平时间比例,从而控制电机的转速。

                5. 超声波模块

`timescale 1ns / 1ps
module SR_04(
        input               clk     ,
        input               rst_n   ,
        input               echo    ,   //接收端,判断端口返回值
        output     [15:0]   dis     ,   //最终距离
        output              trig        //脉冲发出
    );
    
    parameter   delay = (50*15) + (50*1000*100);    //60ms以上的周期
    parameter   s1 = 0;         //空闲
    parameter   s2 = 1;         //echo开始计时
    parameter   s3 = 2;         //计时结束
    
    reg     [31:0]  cnt_trig;
    reg     [31:0]  cnt_echo;
    reg     [31:0]  cnt_echo_reg;
    reg [2:0]   c_state;
    reg [2:0]   n_state;
    
    
    always @(posedge clk)
        if(!rst_n)
            cnt_trig <= 0;
        else if(cnt_trig == delay -1)
            cnt_trig <= 0;
        else
            cnt_trig <= cnt_trig +1
            ;
    assign  trig = ((cnt_trig >0) && (cnt_trig<(50*15))) ? 1:0;
    
    
    always  @(posedge clk)
        if(!rst_n)
            c_state <= s1;
        else
            c_state <= n_state;
            
     always @(*)
        case(c_state)
            s1: begin
                if(echo == 1)
                    n_state = s2;
                else
                    n_state = s1;
                 end
            s2: begin 
                if(echo == 0)
                    n_state = s3;
                else
                    n_state = s2;
            end
            s3: begin
                n_state = s1;
             end
         endcase
    
    
always @(posedge clk)
    if(!rst_n)begin
        cnt_echo<=0;
        cnt_echo_reg <= 0;
    end
    else    begin
            case(c_state)
                s1: begin
                    cnt_echo<=0;
                    cnt_echo_reg <= cnt_echo_reg;
                    end
                s2: begin
                    cnt_echo<=cnt_echo +1;
                    cnt_echo_reg <= cnt_echo_reg;
                   end
                s3: begin
                    cnt_echo<=cnt_echo;
                    cnt_echo_reg <= cnt_echo;
                    end
            endcase
     end
        
        
assign  dis = (cnt_echo_reg * 20)/1000/58;
    
    
endmodule

此处我们只需要调用输出的dis距离进行程序处理即可。

超声波测距模块

                6. 循迹模块

`timescale 1ns / 1ps
module infrared(
        input               clk             ,
        input               rst_n           ,
        input    [1:0]      infrared        ,
        output   reg [1:0]  infrared_data
    );
    
    always  @(posedge clk)
        if(!rst_n)
            infrared_data <= 0;
         else
            infrared_data <= infrared;
            
            
endmodule

这是一个循迹模块,根据输入的红外传感器信号infrared来更新输出的红外数据infrared_data

  1. timescale 1ns / 1ps定义了时间单位和精度。
  2. module infrared定义了模块名和输入输出端口。
  3. always @(posedge clk)表示在时钟上升沿触发的时候执行内部逻辑。
  4. if-else语句用于根据时钟和复位信号的状态更新infrared_data寄存器。
  5. 在复位信号为低电平时,将infrared_data寄存器清零。
  6. 在时钟上升沿时,将输入的红外传感器信号infrared赋值给infrared_data寄存器。

根据上述代码,该模块的功能是将红外传感器的输入信号infrared直接赋值给infrared_data输出寄存器。这样可以将两路循迹模块的输入接口进行处理,以适应主程序控制模块的整体思路。

                7. 主程序

    //      功能  循迹  避障      遥控车
    // 位数        8        7        6        5        4        3        2        1
    //第8位为控制位,控制自动和手动        0 = 自动    1 = 手动
    // 7 6 5 控制方向:                            4     3         2 1 速度:
    //                    010 前进        0XA0        01    遥控车        01 慢速    0X81
    //                    101 后退        0XD0        10    循迹        10 中速    0X82
    //                    001 右转        0X90        11    避障        11 高速    0X83
    //                    100 左转        0XC0
    //                    000 停车        0X80

//针脚配置
    //串口    rx  P20             //左轮控制    左方向:N18   T20         //右轮控制  右方向 P18 U20
    //        tx                                左pwm    P19                         右pwm    V20
    //                            //超声波     teig    W20               //循迹      左   W16
                                        //     echo     R18                         右   R17

                        引脚配置
module car_kz(
        input                   clk         ,
        input                   rst_n       ,
        input                   rx          ,
        output  reg[3:0]        led        ,
            //行驶方向控制
        output reg[1:0]     left_whell     ,
        output reg[1:0]     right_whell    ,
        output               left_pwm       ,
        output               right_pwm      ,
        
                //超声波gpio
        input                   echo             ,//接收端,判断超声波端口返回值
        output                  trig             ,//脉冲发出
                //循迹
        input        [1:0]      infrared
    );     
                        模块引入
rx_dat UART1_RX(
        .   clk         (clk     ),
        .   rst_n       (rst_n   ),
        .   rx          (rx      ),
        .   rx_done     (rx_done ),
        .   rx_data     (rx_data )   
    );
    
led_mk  led_k(
    .   clk     ( clk    )   ,
    .   rst_n   ( rst_n  )   ,
    .   led_zt  ( led_zt )   ,
    .   led     ( led_kz    )
       );
       
 DIRECTION fxkz(
        .     clk               (clk         )  ,
        .     rst_n             (rst_n       )  ,
        .     DIRECTION_zt      (DIRECTION_zt)  ,
        .     left_whell        (left_whell_output  ) ,
        .     right_whell       (right_whell_output ) 
    );
    
  SY6_PWM pwm_db(
    .              clk       ( clk      ) ,
    .              rst_n     ( rst_n    ) ,
    .              speed     ( speed_pwm    ) ,    
    .              left_pwm  ( left_pwm_mk ) ,
    .              right_pwm ( right_pwm_mk)
    );
    
SR_04   SR_CSB(
       .   clk   (clk  ) ,
       .   rst_n (rst_n) ,
       .   echo  (echo ) ,   //接收端,判断端口返回值
       .   dis   (dis  ) ,   //最终距离
       .   trig  (trig )     //脉冲发出
    );
    
infrared    XJ(
        .  clk           (clk          ) ,
        .  rst_n         (rst_n        ) ,
        .  infrared      (infrared_mk     ) ,
        .  infrared_data (infrared_data)
    );
                        模式判断

    wire     [2:0]   car_mode;
    parameter   remote_control_car      = 2'b01;
    parameter   tracking_car            = 2'b10;
    parameter   Avoiding_car           = 2'b11;


   assign  car_mode = rx_data[3:2];
    
    always@(posedge clk)  begin
        if(!rst_n)
            Avoiding_car_cnt <= 0;
        else
            case(car_mode)
                remote_control_car: begin
                            if(rx_data[1:0] == speed1 || rx_data[1:0] == speed2 || rx_data[1:0] == speed3)  begin
                                    speed <= rx_data[1:0]; 
                                end
                            else
                                speed <= speed; 
                            car_run <= rx_data[6:4];  
                    end
                tracking_car:   begin
                         speed <= speed1;  
                         
                         if(infrared_data[1] == 1 && infrared_data[0] == 1)
                             car_run <= stop;
                         else if(infrared_data[1] == 1 && infrared_data[0] == 0)
                             car_run <= turn_left;
                         else if(infrared_data[1] == 0 && infrared_data[0] == 1)
                             car_run <= turn_right;
                          else
                             car_run <= forward;
                            
                    end
                Avoiding_car:   begin
                        //speed <= speed2;
                        //冲突,此处和程序不同,不可同时满足多种情况,        !!!!:不可一循环内先满足后满足,实现后满足情况
                        if(dis <= Avoiding_distance)   begin
                            Avoiding_car_qk <= 1;
                            Avoiding_car_cnt <= 0;
                            speed <= speed1;
                            car_run <= turn_right;
                           end
                        else if(dis > Avoiding_distance && Avoiding_car_qk == 1 && Avoiding_car_cnt <= Avoiding_car_delay - 1)   begin
                                   Avoiding_car_cnt <= Avoiding_car_cnt + 1;
                                    speed <= speed1;
                                    car_run <= turn_right;
                            end
                        else if(Avoiding_car_cnt > Avoiding_car_delay - 1)  begin
                                    Avoiding_car_qk <= 0;
                                    Avoiding_car_cnt <= 0;
                                end
                        else    begin
                            speed <= speed2;
                            car_run <= forward;
                            end
                    end
                default:    begin
                        speed <= speed0;
                        car_run <= stop;
                    end
               endcase
        end

car_mode保存4 3位的数据,确定小车模式(循迹,避障,遥控),Avoiding_car模式中,需要在识别障碍物后转动一部分时间。

                 LED控制

//***************************************   LED控制  *********************************************************//
    //led控制
    always  @(posedge clk)
        if(!rst_n)
            c_speed_led <= led1;
        else
            c_speed_led <= n_speedl_led;

    always  @(*)
        case(speed)
            speed0 :begin
                    n_speedl_led = led1;
                end
            speed1 :begin
                    n_speedl_led = led2;
                end
            speed2 :begin
                    n_speedl_led = led3;
                end
            speed3 :begin
                    n_speedl_led = led4;
                    end
            default:begin
                    n_speedl_led = 0;
                end
        endcase
        
        always  @(posedge clk)
            if(!rst_n)
                led_zt <= 0;
             else
                led_zt <= c_speed_led;
                
        always  @(posedge clk)
            if(!rst_n)
                led <= 0;
             else
                led <= led_kz;
//*************************************************************************************************************//
                        PWM调速

//******************************************    PWM控制车速     **********************************************************//

        //此处直接将led值输入给pwm速度,因为  led在此处用于表达速度
        always  @(posedge clk)
            if(!rst_n)
                speed_pwm <= 0;
             else
                speed_pwm <= c_speed_led * 250;
                
                    assign right_pwm = right_pwm_mk;
                assign left_pwm =  left_pwm_mk;
                
                /*
        always  @(*)
            if(!rst_n)begin
                    left_pwm  = 0;
                    right_pwm = 0;         
            end
             else begin
                    left_pwm  = left_pwm_mk;
                    right_pwm = right_pwm_mk;
            end     */
//*************************************************************************************************************//
                        方向控制

//*************************************     方向控制    **************************************************************// 
    always  @(posedge clk)
        if(!rst_n)
            c_whell_contel <= stop;
        else
            c_whell_contel <= n_whell_contel;

    always  @(*)
        case(car_run)
            forward :begin
                    n_whell_contel = whell_forward;
                end
            retreat :begin
                    n_whell_contel = whell_whell_retreat;
                end
            turn_right :begin
                    n_whell_contel = whell_turn_right;
                end
            turn_left :begin
                    n_whell_contel = whell_turn_left;
                    end
            stop :begin
                    n_whell_contel = whell_stop;
                    end
            default:begin
                    n_whell_contel = whell_stop;
                end
        endcase

        always  @(posedge clk)
            if(!rst_n)
                DIRECTION_zt <= 0;
             else
                DIRECTION_zt <= c_whell_contel;
                
        always  @(posedge clk)
            if(!rst_n)begin
                    left_whell  <= 0;
                    right_whell <= 0;         
            end
             else begin
                    left_whell  <= left_whell_output;
                    right_whell <= right_whell_output;
            end             
//*************************************************************************************************************//
        
                car_kz(最终程序)
`timescale 1ns / 1ps
    //      功能  循迹  避障      遥控车
	// 位数		8		7		6		5		4		3		2		1
	//第8位为控制位,控制自动和手动		0 = 自动	1 = 手动
	// 7 6 5 控制方向:							4     3         2 1 速度:
	//					010 前进		0XA0		01	遥控车		01 慢速	0X81
	//					101 后退		0XD0		10    循迹		10 中速	0X82
	//					001 右转		0X90		11    避障		11 高速	0X83
	//					100 左转		0XC0
	//					000 停车		0X80

//针脚配置
    //串口    rx  P20             //左轮控制    左方向:N18   T20         //右轮控制  右方向 P18 U20
    //        tx                                左pwm    P19                         右pwm    V20
    //                            //超声波     teig    W20               //循迹      左   W16
                                        //     echo     R18                         右   R17
module car_kz(
        input                   clk         ,
        input                   rst_n       ,
        input                   rx          ,
        output  reg[3:0]        led        ,
            //行驶方向控制
        output reg[1:0]     left_whell     ,
        output reg[1:0]     right_whell    ,
        output               left_pwm       ,
        output               right_pwm      ,
        
                //超声波gpio
        input                   echo             ,//接收端,判断超声波端口返回值
        output                  trig             ,//脉冲发出
                //循迹
        input        [1:0]      infrared
    );                                        
    
    //小车状态
            //处理小车状态
    //wire     [2:0]   car_mode;
    wire     [2:0]   car_mode;
    parameter   remote_control_car      = 2'b01;
    parameter   tracking_car            = 2'b10;
    parameter   Avoiding_car           = 2'b11;
            //速度
    parameter   speed0 = 2'b00;
    parameter   speed1 = 2'b01;
    parameter   speed2 = 2'b10;
    parameter   speed3 = 2'b11;
    //wire [2:0]   speed;
    reg [2:0]   speed;
    reg  [31:0]   speed_pwm;
            //控制方向
    //wire [2:0]   car_run;   
    reg [2:0]   car_run;   
    parameter   forward     = 3'b010;
    parameter   retreat     = 3'b101;
    parameter   turn_right  = 3'b001;
    parameter   turn_left   = 3'b100;
    parameter   stop        = 3'b000;
                    //方向状态机
    reg     [4:0]   c_whell_contel;
    reg     [4:0]   n_whell_contel;
    reg     [4:0]   DIRECTION_zt    ;       //处理方向控制状态
    wire    [1:0]   left_whell_output;
    wire    [1:0]   right_whell_output;
    parameter   whell_forward           = 0 ;
    parameter   whell_whell_retreat     = 1 ;
    parameter   whell_turn_right        = 2 ;
    parameter   whell_turn_left         = 3 ;
    parameter   whell_stop              = 4 ;
        //超声波
    wire  [15:0]  dis;  //获取超声波距离   单位  cm
    parameter   Avoiding_car_delay = 50_000_000 ;
    parameter   Avoiding_distance   = 20;   //避障距离
    reg [31:0]   Avoiding_car_cnt;
    reg  [2:0]  Avoiding_car_qk;
        //循迹
    wire    [1:0]   infrared_data;
    reg     [1:0]   infrared_mk;
    
    //led相关控制
    reg  [4:0]  led_zt;
    wire    [3:0]  led_kz;
    parameter led1 = 0;
    parameter led2 = 1;
    parameter led3 = 2;
    parameter led4 = 3;
    parameter led5 = 4;
    reg     [4:0]   c_speed_led;
    reg     [4:0]   n_speedl_led;
    
    //串口相关控制
    wire rx_done;
    wire [7:0]   rx_data;
    reg  [7:0]   data;
    
    //
     wire   left_pwm_mk;
     wire   right_pwm_mk;
    
    //处理接收信号
    
   //assign  speed = rx_data[1:0];           
   //assign  car_run = rx_data[6:4];
   assign  car_mode = rx_data[3:2];
    
    always@(posedge clk)  begin
        if(!rst_n)
            Avoiding_car_cnt <= 0;
        else
            case(car_mode)
                remote_control_car: begin
                            if(rx_data[1:0] == speed1 || rx_data[1:0] == speed2 || rx_data[1:0] == speed3)  begin
                                    speed <= rx_data[1:0]; 
                                end
                            else
                                speed <= speed; 
                            car_run <= rx_data[6:4];  
                    end
                tracking_car:   begin
                         speed <= speed1;  
                         
                         if(infrared_data[1] == 1 && infrared_data[0] == 1)
                             car_run <= stop;
                         else if(infrared_data[1] == 1 && infrared_data[0] == 0)
                             car_run <= turn_left;
                         else if(infrared_data[1] == 0 && infrared_data[0] == 1)
                             car_run <= turn_right;
                          else
                             car_run <= forward;
                            
                    end
                Avoiding_car:   begin
                        //speed <= speed2;
                        //冲突,此处和程序不同,不可同时满足多种情况,        !!!!:不可一循环内先满足后满足,实现后满足情况
                        if(dis <= Avoiding_distance)   begin
                            Avoiding_car_qk <= 1;
                            Avoiding_car_cnt <= 0;
                            speed <= speed1;
                            car_run <= turn_right;
                           end
                        else if(dis > Avoiding_distance && Avoiding_car_qk == 1 && Avoiding_car_cnt <= Avoiding_car_delay - 1)   begin
                                   Avoiding_car_cnt <= Avoiding_car_cnt + 1;
                                    speed <= speed1;
                                    car_run <= turn_right;
                            end
                        else if(Avoiding_car_cnt > Avoiding_car_delay - 1)  begin
                                    Avoiding_car_qk <= 0;
                                    Avoiding_car_cnt <= 0;
                                end
                        else    begin
                            speed <= speed2;
                            car_run <= forward;
                            end
                    end
                default:    begin
                        speed <= speed0;
                        car_run <= stop;
                    end
               endcase
        end
        
//***************************************       超声波避障处理        ********************************************************//
/*always @(posedge clk)
    if(!rst_n)begin
        Avoiding_car_qk <= 0;
        Avoiding_car_cnt <= 0;
        //speed <= speed1;
        //car_run <= turn_right;
        end
     else  if(Avoiding_car_qk == 1 && Avoiding_car_cnt <= Avoiding_car_delay - 1 && dis > 20)begin
            speed <= speed1;
            car_run <= turn_right;
            Avoiding_car_cnt <= Avoiding_car_cnt + 1;
                                
            if(Avoiding_car_cnt >Avoiding_car_delay - 1)   begin
                Avoiding_car_cnt <= 0;
                Avoiding_car_qk <= 0;
                end
            end
      else  begin
        Avoiding_car_qk <= Avoiding_car_qk;
        Avoiding_car_cnt <= Avoiding_car_cnt;
       end
            
        */
     
     
        
//*************************************************************************************************************//


//***************************************************   循迹控制   *********************************************//
        always  @(posedge clk)
            if(!rst_n)
                infrared_mk <= 0;
             else
                infrared_mk <= infrared;

//*************************************************************************************************************//
        

//***************************************   LED控制  *********************************************************//
    //led控制
    always  @(posedge clk)
        if(!rst_n)
            c_speed_led <= led1;
        else
            c_speed_led <= n_speedl_led;

    always  @(*)
        case(speed)
            speed0 :begin
                    n_speedl_led = led1;
                end
            speed1 :begin
                    n_speedl_led = led2;
                end
            speed2 :begin
                    n_speedl_led = led3;
                end
            speed3 :begin
                    n_speedl_led = led4;
                    end
            default:begin
                    n_speedl_led = 0;
                end
        endcase
        
        always  @(posedge clk)
            if(!rst_n)
                led_zt <= 0;
             else
                led_zt <= c_speed_led;
                
        always  @(posedge clk)
            if(!rst_n)
                led <= 0;
             else
                led <= led_kz;
//*************************************************************************************************************//



//******************************************    PWM控制车速     **********************************************************//

        //此处直接将led值输入给pwm速度,因为  led在此处用于表达速度
        always  @(posedge clk)
            if(!rst_n)
                speed_pwm <= 0;
             else
                speed_pwm <= c_speed_led * 250;
                
                    assign right_pwm = right_pwm_mk;
                assign left_pwm =  left_pwm_mk;
                
                /*
        always  @(*)
            if(!rst_n)begin
                    left_pwm  = 0;
                    right_pwm = 0;         
            end
             else begin
                    left_pwm  = left_pwm_mk;
                    right_pwm = right_pwm_mk;
            end     */
//*************************************************************************************************************//



//*************************************     方向控制    **************************************************************// 
    always  @(posedge clk)
        if(!rst_n)
            c_whell_contel <= stop;
        else
            c_whell_contel <= n_whell_contel;

    always  @(*)
        case(car_run)
            forward :begin
                    n_whell_contel = whell_forward;
                end
            retreat :begin
                    n_whell_contel = whell_whell_retreat;
                end
            turn_right :begin
                    n_whell_contel = whell_turn_right;
                end
            turn_left :begin
                    n_whell_contel = whell_turn_left;
                    end
            stop :begin
                    n_whell_contel = whell_stop;
                    end
            default:begin
                    n_whell_contel = whell_stop;
                end
        endcase

        always  @(posedge clk)
            if(!rst_n)
                DIRECTION_zt <= 0;
             else
                DIRECTION_zt <= c_whell_contel;
                
        always  @(posedge clk)
            if(!rst_n)begin
                    left_whell  <= 0;
                    right_whell <= 0;         
            end
             else begin
                    left_whell  <= left_whell_output;
                    right_whell <= right_whell_output;
            end             
//*************************************************************************************************************//
        
rx_dat UART1_RX(
        .   clk         (clk     ),
        .   rst_n       (rst_n   ),
        .   rx          (rx      ),
        .   rx_done     (rx_done ),
        .   rx_data     (rx_data )   
    );
    
led_mk  led_k(
    .   clk     ( clk    )   ,
    .   rst_n   ( rst_n  )   ,
    .   led_zt  ( led_zt )   ,
    .   led     ( led_kz    )
       );
       
 DIRECTION fxkz(
        .     clk               (clk         )  ,
        .     rst_n             (rst_n       )  ,
        .     DIRECTION_zt      (DIRECTION_zt)  ,
        .     left_whell        (left_whell_output  ) ,
        .     right_whell       (right_whell_output ) 
    );
    
  SY6_PWM pwm_db(
    .              clk       ( clk      ) ,
    .              rst_n     ( rst_n    ) ,
    .              speed     ( speed_pwm    ) ,    
    .              left_pwm  ( left_pwm_mk ) ,
    .              right_pwm ( right_pwm_mk)
    );
    
SR_04   SR_CSB(
       .   clk   (clk  ) ,
       .   rst_n (rst_n) ,
       .   echo  (echo ) ,   //接收端,判断端口返回值
       .   dis   (dis  ) ,   //最终距离
       .   trig  (trig )     //脉冲发出
    );
    
infrared    XJ(
        .  clk           (clk          ) ,
        .  rst_n         (rst_n        ) ,
        .  infrared      (infrared_mk     ) ,
        .  infrared_data (infrared_data)
    );
endmodule

        STM32F103C8T6遥控器

                1. 4*4按键矩阵

输出引脚5、6、7、8设置为高电平,输入引脚1、2、3、4进行信号接收

matrix_4x4.c

#include "matrix_4x4.h"
#include "gpio.h"

void matrix_4x4_init(void)
{
	HAL_GPIO_WritePin(P4_5_GPIO_Port, P4_5_Pin, H);
	HAL_GPIO_WritePin(P4_6_GPIO_Port, P4_6_Pin, H);
	HAL_GPIO_WritePin(P4_7_GPIO_Port, P4_7_Pin, H);
	HAL_GPIO_WritePin(P4_8_GPIO_Port, P4_8_Pin, H);
}

void matrix_4x4_1100(void)
{
	HAL_GPIO_WritePin(P4_5_GPIO_Port, P4_5_Pin, H);
	HAL_GPIO_WritePin(P4_6_GPIO_Port, P4_6_Pin, H);
	HAL_GPIO_WritePin(P4_7_GPIO_Port, P4_7_Pin, L);
	HAL_GPIO_WritePin(P4_8_GPIO_Port, P4_8_Pin, L);
}


void matrix_4x4_0011(void)
{
	HAL_GPIO_WritePin(P4_5_GPIO_Port, P4_5_Pin, L);
	HAL_GPIO_WritePin(P4_6_GPIO_Port, P4_6_Pin, L);
	HAL_GPIO_WritePin(P4_7_GPIO_Port, P4_7_Pin, H);
	HAL_GPIO_WritePin(P4_8_GPIO_Port, P4_8_Pin, H);
}


void matrix_4x4_1000(void)
{
	HAL_GPIO_WritePin(P4_5_GPIO_Port, P4_5_Pin, H);
	HAL_GPIO_WritePin(P4_6_GPIO_Port, P4_6_Pin, L);
	HAL_GPIO_WritePin(P4_7_GPIO_Port, P4_7_Pin, L);
	HAL_GPIO_WritePin(P4_8_GPIO_Port, P4_8_Pin, L);
}


void matrix_4x4_0100(void)
{
	HAL_GPIO_WritePin(P4_5_GPIO_Port, P4_5_Pin, L);
	HAL_GPIO_WritePin(P4_6_GPIO_Port, P4_6_Pin, H);
	HAL_GPIO_WritePin(P4_7_GPIO_Port, P4_7_Pin, L);
	HAL_GPIO_WritePin(P4_8_GPIO_Port, P4_8_Pin, L);
}

void matrix_4x4_0010(void)
{
	HAL_GPIO_WritePin(P4_5_GPIO_Port, P4_5_Pin, L);
	HAL_GPIO_WritePin(P4_6_GPIO_Port, P4_6_Pin, L);
	HAL_GPIO_WritePin(P4_7_GPIO_Port, P4_7_Pin, H);
	HAL_GPIO_WritePin(P4_8_GPIO_Port, P4_8_Pin, L);
}


void matrix_4x4_0001(void)
{
	HAL_GPIO_WritePin(P4_5_GPIO_Port, P4_5_Pin, L);
	HAL_GPIO_WritePin(P4_6_GPIO_Port, P4_6_Pin, L);
	HAL_GPIO_WritePin(P4_7_GPIO_Port, P4_7_Pin, L);
	HAL_GPIO_WritePin(P4_8_GPIO_Port, P4_8_Pin, H);
}




//4*4矩阵按键
/*uint8_t matrix_4x4(void)
{
	matrix_4x4_init();
	HAL_Delay(50);
	uint8_t		matrix_4x4_input[4] = {0,0,0,0};
	if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
		matrix_4x4_input[0] = 1;
	if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
		matrix_4x4_input[1] = 1;
	if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
		matrix_4x4_input[2] = 1;
	if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
		matrix_4x4_input[3] = 1;
}*/


uint8_t matrix_4x4(void)
{
	matrix_4x4_init();
	int i = 50;
	HAL_Delay(i);
	static uint8_t matrix_4x4_number = 0;	//输出结果	莫个按键
	uint8_t		matrix_4x4_input[4] = {0,0,0,0};
	if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
		matrix_4x4_input[0] = 1;
	if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
		matrix_4x4_input[1] = 1;
	if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
		matrix_4x4_input[2] = 1;
	if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
		matrix_4x4_input[3] = 1;
	
	//if(matrix_4x4_input != 0)
	if(matrix_4x4_input[0] == 1 || matrix_4x4_input[1] == 1 || matrix_4x4_input[2] == 1 || matrix_4x4_input[3] == 1)
	{
		HAL_Delay(i);	
		//uint8_t	matrix_4x4_output_n[4];
		/*
		matrix_4x4_output_n[0] = 1;
		matrix_4x4_output_n[1] = 1;
		matrix_4x4_output_n[2] = 0;
		matrix_4x4_output_n[3] = 0;
		matrix_4x4_output(matrix_4x4_output_n);*/
		matrix_4x4_1100();
		HAL_Delay(i);	//等待电平变化	
		
		//再次判断状态
		if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
			matrix_4x4_input[0] = 1;
		else
			matrix_4x4_input[0] = 0;
		if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
			matrix_4x4_input[1] = 1;
		else
			matrix_4x4_input[1] = 0;
		if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
			matrix_4x4_input[2] = 1;
		else
			matrix_4x4_input[2] = 0;
		if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
			matrix_4x4_input[3] = 1;
		else
			matrix_4x4_input[3] = 0;
		
		//1100
		//if(matrix_4x4_input != 0)
		if(matrix_4x4_input[0] == 1 || matrix_4x4_input[1] == 1 || matrix_4x4_input[2] == 1 || matrix_4x4_input[3] == 1)
		{
			//1000
			HAL_Delay(i);	
			/*
			matrix_4x4_output_n[0] = 1;
			matrix_4x4_output_n[1] = 0;
			matrix_4x4_output_n[2] = 0;
			matrix_4x4_output_n[3] = 0;
			matrix_4x4_output(matrix_4x4_output_n);*/
			matrix_4x4_1000();
			HAL_Delay(i);	//等待电平变化	
			
					//再次判断状态
			if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
				matrix_4x4_input[0] = 1;
			else
				matrix_4x4_input[0] = 0;
			if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
				matrix_4x4_input[1] = 1;
			else
				matrix_4x4_input[1] = 0;
			if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
				matrix_4x4_input[2] = 1;
			else
				matrix_4x4_input[2] = 0;
			if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
				matrix_4x4_input[3] = 1;
			else
				matrix_4x4_input[3] = 0;
			
			//if(matrix_4x4_input != 0)
			if(matrix_4x4_input[0] == 1 || matrix_4x4_input[1] == 1 || matrix_4x4_input[2] == 1 || matrix_4x4_input[3] == 1)
			{
				//再次判断状态
				if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
					matrix_4x4_number = 4;
				else
					matrix_4x4_number = matrix_4x4_number;
				if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
					matrix_4x4_number = 3;
				else
					matrix_4x4_number = matrix_4x4_number;
				if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
					matrix_4x4_number = 2;
				else
					matrix_4x4_number = matrix_4x4_number;
				if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
					matrix_4x4_number = 1;
				else
					matrix_4x4_number = matrix_4x4_number;
			}
			else
			{	//0100
				HAL_Delay(i);
				/*
				matrix_4x4_output_n[0] = 0;
				matrix_4x4_output_n[1] = 1;
				matrix_4x4_output_n[2] = 0;
				matrix_4x4_output_n[3] = 0;
				matrix_4x4_output(matrix_4x4_output_n);*/
				matrix_4x4_0100();
				HAL_Delay(i);	//等待电平变化	
				
				//再次判断状态
				if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
					matrix_4x4_number = 8;
				else
					matrix_4x4_number = matrix_4x4_number;
				if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
					matrix_4x4_number = 7;
				else
					matrix_4x4_number = matrix_4x4_number;
				if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
					matrix_4x4_number = 6;
				else
					matrix_4x4_number = matrix_4x4_number;
				if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
					matrix_4x4_number = 5;
				else
					matrix_4x4_number = matrix_4x4_number;
				
			}
		}
		else
		{
			//0011
			HAL_Delay(i);	
			/*
			uint8_t	matrix_4x4_output_n[4];
			matrix_4x4_output_n[0] = 0;
			matrix_4x4_output_n[1] = 0;
			matrix_4x4_output_n[2] = 1;
			matrix_4x4_output_n[3] = 1;
			matrix_4x4_output(matrix_4x4_output_n);*/
			matrix_4x4_0011();
			HAL_Delay(i);	//等待电平变化	
			
			//再次判断状态
			if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
				matrix_4x4_input[0] = 1;
			else
				matrix_4x4_input[0] = 0;
			if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
				matrix_4x4_input[1] = 1;
			else
				matrix_4x4_input[1] = 0;
			if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
				matrix_4x4_input[2] = 1;
			else
				matrix_4x4_input[2] = 0;
			if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
				matrix_4x4_input[3] = 1;
			else
				matrix_4x4_input[3] = 0;
			
			
			//if(matrix_4x4_input != 0)
			if(matrix_4x4_input[0] == 1 || matrix_4x4_input[1] == 1 || matrix_4x4_input[2] == 1 || matrix_4x4_input[3] == 1)
			{
				//0010
				HAL_Delay(i);	
				/*
				matrix_4x4_output_n[0] = 0;
				matrix_4x4_output_n[1] = 0;
				matrix_4x4_output_n[2] = 1;
				matrix_4x4_output_n[3] = 0;
				matrix_4x4_output(matrix_4x4_output_n);*/
				matrix_4x4_0010();
				HAL_Delay(i);	//等待电平变化	
				
				//再次判断状态
				if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
					matrix_4x4_input[0] = 1;
				else
					matrix_4x4_input[0] = 0;
				if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
					matrix_4x4_input[1] = 1;
				else
					matrix_4x4_input[1] = 0;
				if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
					matrix_4x4_input[2] = 1;
				else
					matrix_4x4_input[2] = 0;
				if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
					matrix_4x4_input[3] = 1;
				else
					matrix_4x4_input[3] = 0;
				

				//if(matrix_4x4_input != 0)
				if(matrix_4x4_input[0] == 1 || matrix_4x4_input[1] == 1 || matrix_4x4_input[2] == 1 || matrix_4x4_input[3] == 1)
				{
					//再次判断状态
					if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
						matrix_4x4_number = 12;
					else
						matrix_4x4_number = matrix_4x4_number;
					if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
						matrix_4x4_number = 11;
					else
						matrix_4x4_number = matrix_4x4_number;
					if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
						matrix_4x4_number = 10;
					else
						matrix_4x4_number = matrix_4x4_number;
					if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
						matrix_4x4_number = 9;
					else
						matrix_4x4_number = matrix_4x4_number;
				}
				else
				{	//0001
					HAL_Delay(i);
					/*
					matrix_4x4_output_n[0] = 0;
					matrix_4x4_output_n[1] = 0;
					matrix_4x4_output_n[2] = 0;
					matrix_4x4_output_n[3] = 1;
					matrix_4x4_output(matrix_4x4_output_n);*/
					matrix_4x4_0001();
					HAL_Delay(i);	//等待电平变化	
					
					//再次判断状态
					if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
						matrix_4x4_number = 16;
					else
						matrix_4x4_number = matrix_4x4_number;
					if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
						matrix_4x4_number = 15;
					else
						matrix_4x4_number = matrix_4x4_number;
					if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
						matrix_4x4_number = 14;
					else
						matrix_4x4_number = matrix_4x4_number;
					if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
						matrix_4x4_number = 13;
					else
						matrix_4x4_number = matrix_4x4_number;
					
				}
			}
		}
	}
	return	matrix_4x4_number;
}




void matrix_4x4_output(uint8_t i[4])
{
	if(i[0] == 0)
		HAL_GPIO_WritePin(P4_5_GPIO_Port, P4_5_Pin, L);
	else
		HAL_GPIO_WritePin(P4_5_GPIO_Port, P4_5_Pin, H);	
		
	if(i[1] == 0)
		HAL_GPIO_WritePin(P4_6_GPIO_Port, P4_6_Pin, L);
	else
		HAL_GPIO_WritePin(P4_6_GPIO_Port, P4_6_Pin, H);	
		
	if(i[2] == 0)
		HAL_GPIO_WritePin(P4_7_GPIO_Port, P4_7_Pin, L);
	else
		HAL_GPIO_WritePin(P4_7_GPIO_Port, P4_7_Pin, H);	
		
	if(i[3] == 0)
		HAL_GPIO_WritePin(P4_8_GPIO_Port, P4_8_Pin, L);
	else
		HAL_GPIO_WritePin(P4_8_GPIO_Port, P4_8_Pin, H);	
		
	/*
	HAL_GPIO_WritePin(P4_5_GPIO_Port, P4_5_Pin, H);
	HAL_GPIO_WritePin(P4_6_GPIO_Port, P4_6_Pin, H);
	HAL_GPIO_WritePin(P4_7_GPIO_Port, P4_7_Pin, H);
	HAL_GPIO_WritePin(P4_8_GPIO_Port, P4_8_Pin, H);	
	*/
}

/*
#include "matrix_4x4.h"
#include "gpio.h"

void matrix_4x4_init(void)
{
	HAL_GPIO_WritePin(P4_5_GPIO_Port, P4_5_Pin, H);
	HAL_GPIO_WritePin(P4_6_GPIO_Port, P4_6_Pin, H);
	HAL_GPIO_WritePin(P4_7_GPIO_Port, P4_7_Pin, H);
	HAL_GPIO_WritePin(P4_8_GPIO_Port, P4_8_Pin, H);
}

//4*4矩阵按键
uint8_t matrix_4x4(void)
{
	matrix_4x4_init();
	HAL_Delay(50);
	int matrix_4x4_number = 0;	//输出结果	莫个按键
	uint8_t		matrix_4x4_input[4] = {0,0,0,0};
	if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
		matrix_4x4_input[0] = 1;
	if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
		matrix_4x4_input[1] = 1;
	if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
		matrix_4x4_input[2] = 1;
	if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
		matrix_4x4_input[3] = 1;
	
	
	if(matrix_4x4_input != 0)
	{
		HAL_Delay(20);	
		uint8_t	matrix_4x4_output_n[4];
		matrix_4x4_output_n[0] = 1;
		matrix_4x4_output_n[1] = 1;
		matrix_4x4_output_n[2] = 0;
		matrix_4x4_output_n[3] = 0;
		matrix_4x4_output(matrix_4x4_output_n);
		HAL_Delay(100);	//等待电平变化	
		
		//再次判断状态
		if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
			matrix_4x4_input[0] = 1;
		else
			matrix_4x4_input[0] = 0;
		if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
			matrix_4x4_input[1] = 1;
		else
			matrix_4x4_input[1] = 0;
		if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
			matrix_4x4_input[2] = 1;
		else
			matrix_4x4_input[2] = 0;
		if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
			matrix_4x4_input[3] = 1;
		else
			matrix_4x4_input[3] = 0;
		
		//1100
		if(matrix_4x4_input != 0)
		{
			//1000
			HAL_Delay(20);	
			matrix_4x4_output_n[0] = 1;
			matrix_4x4_output_n[1] = 0;
			matrix_4x4_output_n[2] = 0;
			matrix_4x4_output_n[3] = 0;
			matrix_4x4_output(matrix_4x4_output_n);
			HAL_Delay(100);	//等待电平变化	
			
			
			//再次判断状态
			if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
				matrix_4x4_number = 4;
			else
				matrix_4x4_number = matrix_4x4_number;
			if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
				matrix_4x4_number = 3;
			else
				matrix_4x4_number = matrix_4x4_number;
			if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
				matrix_4x4_number = 2;
			else
				matrix_4x4_number = matrix_4x4_number;
			if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
				matrix_4x4_number = 1;
			else
				matrix_4x4_number = matrix_4x4_number;
		}
		
		else
		{	//0100
			HAL_Delay(20);
			matrix_4x4_output_n[0] = 0;
			matrix_4x4_output_n[1] = 1;
			matrix_4x4_output_n[2] = 0;
			matrix_4x4_output_n[3] = 0;
			matrix_4x4_output(matrix_4x4_output_n);
			HAL_Delay(100);	//等待电平变化	
			
			//再次判断状态
			if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
				matrix_4x4_number = 8;
			else
				matrix_4x4_number = matrix_4x4_number;
			if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
				matrix_4x4_number = 7;
			else
				matrix_4x4_number = matrix_4x4_number;
			if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
				matrix_4x4_number = 6;
			else
				matrix_4x4_number = matrix_4x4_number;
			if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
				matrix_4x4_number = 5;
			else
				matrix_4x4_number = matrix_4x4_number;
			
		}
		
	}
	else
	{
		//0011
		HAL_Delay(20);	
		uint8_t	matrix_4x4_output_n[4];
		matrix_4x4_output_n[0] = 0;
		matrix_4x4_output_n[1] = 0;
		matrix_4x4_output_n[2] = 1;
		matrix_4x4_output_n[3] = 1;
		matrix_4x4_output(matrix_4x4_output_n);
		HAL_Delay(100);	//等待电平变化	
		
		//再次判断状态
		if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
			matrix_4x4_input[0] = 1;
		else
			matrix_4x4_input[0] = 0;
		if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
			matrix_4x4_input[1] = 1;
		else
			matrix_4x4_input[1] = 0;
		if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
			matrix_4x4_input[2] = 1;
		else
			matrix_4x4_input[2] = 0;
		if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
			matrix_4x4_input[3] = 1;
		else
			matrix_4x4_input[3] = 0;
		
		
		if(matrix_4x4_input != 0)
		{
			//0010
			HAL_Delay(20);	
			matrix_4x4_output_n[0] = 0;
			matrix_4x4_output_n[1] = 0;
			matrix_4x4_output_n[2] = 1;
			matrix_4x4_output_n[3] = 0;
			matrix_4x4_output(matrix_4x4_output_n);
			HAL_Delay(100);	//等待电平变化	
			
			//再次判断状态
			if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
				matrix_4x4_number = 12;
			else
				matrix_4x4_number = matrix_4x4_number;
			if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
				matrix_4x4_number = 11;
			else
				matrix_4x4_number = matrix_4x4_number;
			if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
				matrix_4x4_number = 10;
			else
				matrix_4x4_number = matrix_4x4_number;
			if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
				matrix_4x4_number = 9;
			else
				matrix_4x4_number = matrix_4x4_number;
		}
		else
		{	//0001
			HAL_Delay(20);
			matrix_4x4_output_n[0] = 0;
			matrix_4x4_output_n[1] = 0;
			matrix_4x4_output_n[2] = 0;
			matrix_4x4_output_n[3] = 1;
			matrix_4x4_output(matrix_4x4_output_n);
			HAL_Delay(100);	//等待电平变化	
			
			//再次判断状态
			if(HAL_GPIO_ReadPin(P4_1_GPIO_Port, P4_1_Pin) == H)
				matrix_4x4_number = 16;
			else
				matrix_4x4_number = matrix_4x4_number;
			if(HAL_GPIO_ReadPin(P4_2_GPIO_Port, P4_2_Pin) == H)
				matrix_4x4_number = 15;
			else
				matrix_4x4_number = matrix_4x4_number;
			if(HAL_GPIO_ReadPin(P4_3_GPIO_Port, P4_3_Pin) == H)
				matrix_4x4_number = 14;
			else
				matrix_4x4_number = matrix_4x4_number;
			if(HAL_GPIO_ReadPin(P4_4_GPIO_Port, P4_4_Pin) == H)
				matrix_4x4_number = 13;
			else
				matrix_4x4_number = matrix_4x4_number;
			
		}
		
	}
	
	return	matrix_4x4_number;
}


void matrix_4x4_output(uint8_t i[4])
{
	if(i[0] == 0)
		HAL_GPIO_WritePin(P4_5_GPIO_Port, P4_5_Pin, L);
	else
		HAL_GPIO_WritePin(P4_5_GPIO_Port, P4_5_Pin, H);	
		
	if(i[1] == 0)
		HAL_GPIO_WritePin(P4_6_GPIO_Port, P4_6_Pin, L);
	else
		HAL_GPIO_WritePin(P4_6_GPIO_Port, P4_6_Pin, H);	
		
	if(i[2] == 0)
		HAL_GPIO_WritePin(P4_7_GPIO_Port, P4_7_Pin, L);
	else
		HAL_GPIO_WritePin(P4_7_GPIO_Port, P4_7_Pin, H);	
		
	if(i[3] == 0)
		HAL_GPIO_WritePin(P4_8_GPIO_Port, P4_8_Pin, L);
	else
		HAL_GPIO_WritePin(P4_8_GPIO_Port, P4_8_Pin, H);	
		

}

*/

   matrix_4x4.h

#ifndef MATRIX_4X4_H
#define MATRIX_4X4_H

#include <stdint.h>

#define MATRIX_ROWS 4
#define MATRIX_COLS 4

#define H 				GPIO_PIN_SET 		//GPIO_PIN_SET				1
#define L 				GPIO_PIN_RESET 		//GPIO_PIN_RESET			0
uint8_t matrix_4x4(void);
void matrix_4x4_init(void);

void matrix_4x4_output(uint8_t i[4]);

void matrix_4x4_1100(void);

void matrix_4x4_0011(void);

void matrix_4x4_1000(void);

void matrix_4x4_0100(void);

void matrix_4x4_0010(void);

void matrix_4x4_0001(void);
#endif /* MATRIX_4X4_H */

2. 主程序

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "matrix_4x4.h"
#include "oled.h"
#include "Number.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */


/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

	//4*4按键初始化
	//uint8_t m4x4 = 0;
	uint8_t	m4x4_sz[1];
	//初始化oled
	OLED_Init();	//初始化oled
	OLED_Clear(); 	//清屏
	HAL_Delay(100);
	
	OLED_ShowCHinese(0, 0, 0);
	OLED_ShowCHinese(16, 0, 1);
	//OLED_ShowCHinese(32, 0, 2);
	
	OLED_ShowCHinese(60, 0, 3);
	OLED_ShowCHinese(76, 0, 4);
	OLED_ShowCHinese(92, 0, 2);
	
	//OLED_ShowCHinese(98, 0, 3);
	//OLED_ShowCHinese(114, 0, 4);
	
	//初始化发送数据
	uint8_t data[1] = {0x00};
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  m4x4_sz[0] = matrix_4x4();
	  //
	  //	低速		前进			1		3
	  //	中速   左转  停止 右转		5	6	7	8
	  //	高速		后退			9		11
	  //	   	   避障 循迹 遥控			14  15  16
	  //	   
	  //
	  //
	  //
	switch(m4x4_sz[0] ){
		case 13:
			{
			data[0] = change_bit(data[0], 1, 1);
			data[0] = change_bit(data[0], 2, 0);
			OLED_ShowCHinese(98, 6, 11);
			OLED_ShowCHinese(114, 6, 14);
			break; 
		}
		   
		case 2:
		   break; 
		case 3:
			{
			data[0] = change_bit(data[0], 7, 0);
			data[0] = change_bit(data[0], 6, 1);
			data[0] = change_bit(data[0], 5, 0);
			OLED_ShowCHinese(44, 2, 15);
			OLED_ShowCHinese(60, 2, 16);
			break; 
		}
		case 4:
			{
			data[0] = change_bit(data[0], 7, 1);
			data[0] = change_bit(data[0], 6, 0);
			data[0] = change_bit(data[0], 5, 1);
			OLED_ShowCHinese(44, 2, 17);
			OLED_ShowCHinese(60, 2, 18);
			break; 
		}
		case 5:
			{
			data[0] = change_bit(data[0], 1, 0);
			data[0] = change_bit(data[0], 2, 1);
			OLED_ShowCHinese(98, 6, 12);
			OLED_ShowCHinese(114, 6, 14);
			break; 
		}
		case 6:
			{
			data[0] = change_bit(data[0], 7, 1);
			data[0] = change_bit(data[0], 6, 0);
			data[0] = change_bit(data[0], 5, 0);
			OLED_ShowCHinese(44, 2, 19);
			OLED_ShowCHinese(60, 2, 21);
			break; 
		}
		case 7:
			{
			data[0] = change_bit(data[0], 7, 0);
			data[0] = change_bit(data[0], 6, 0);
			data[0] = change_bit(data[0], 5, 0);
			OLED_ShowCHinese(44, 2, 22);
			OLED_ShowCHinese(60, 2, 23);
			break; 
		}
		case 8:
			{
			data[0] = change_bit(data[0], 7, 0);
			data[0] = change_bit(data[0], 6, 0);
			data[0] = change_bit(data[0], 5, 1);
			OLED_ShowCHinese(44, 2, 20);
			OLED_ShowCHinese(60, 2, 21);
			break; 
		}
		case 9:
			{
			data[0] = change_bit(data[0], 1, 1);
			data[0] = change_bit(data[0], 2, 1);
			OLED_ShowCHinese(98, 6, 13);
			OLED_ShowCHinese(114, 6, 14);
			break; 
		}
		case 10:
		   break; 
		case 11:
			{
			data[0] = change_bit(data[0], 7, 1);
			data[0] = change_bit(data[0], 6, 0);
			data[0] = change_bit(data[0], 5, 1);
			OLED_ShowCHinese(44, 2, 17);
			OLED_ShowCHinese(60, 2, 18);
			break; 
		}
		case 12:
		   break; 
		case 1:
		   break; 
		case 14:
			{
			data[0] = change_bit(data[0], 4, 0);
			data[0] = change_bit(data[0], 3, 1);
			OLED_ShowCHinese(98, 0, 9);
			OLED_ShowCHinese(114, 0, 10);
			break; 
		}
		case 15:
			{
			data[0] = change_bit(data[0], 4, 1);
			data[0] = change_bit(data[0], 3, 0);
			OLED_ShowCHinese(98, 0, 5);
			OLED_ShowCHinese(114, 0, 6);
			break; 
		}
		case 16:
			{
			data[0] = change_bit(data[0], 4, 1);
			data[0] = change_bit(data[0], 3, 1);
			OLED_ShowCHinese(98, 0, 7);
			OLED_ShowCHinese(114, 0, 8);
			break; 
		}

		default :
		   ;
	}		

	  OLED_ShowNum(32, 0, m4x4_sz[0], 2, 16);
	  HAL_UART_Transmit(&huart1, &data[0], 1,0xffff);
	  //HAL_UART_Transmit(&huart1, "\r\n", 4,10);
	  //HAL_Delay(10);
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */



/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0X78

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值