关于PLIC中断



  • 我使用的开发板为35T,内核为perfxlab的risc-v内核。请问如何通过GPIO调用button k1~k4实现硬件(外部)中断。



  • @yclylyf 网盘提供的压缩包是蜂鸟e203的



  • @chshwei @traits
    感谢两位回复,我使用的内核是客服发给我的vivado project,压缩包名字为“35T”,我推测应该是x-core



  • 没有与你要求相同的demo,你可以参考mini_car的中定时器中断设置的代码,配置按键中断,下面代码是mini_car的,仅供参考

    // See LICENSE for license details.
    /**************************************************************
     ** 作者: Alvin Xu of PerfXLab
     ** 本程序展示了蜂鸟的PWM功能,蜂鸟中定义了PWM0、PWM1、PWM2三个PWM控制寄存器,每个PWMx可以输出
     ** 4路PWM波,所以最多可以提供12路PWM波输出。本程序用到了PWM1的4路PWM波输出
     **
     ** 引脚硬件连接
     ** PWM输出,本程序用到了D3和D4输出
     ** PWM1_0用PWM_CMP0控制占空比,对应D4引脚(20)
     ** PWM1_1用PWM_CMP1控制占空比,对应D3_SCL引脚(19)
     ** PWM1_2用PWM_CMP2控制占空比,对应D5引脚(21)
     ** PWM1_3用PWM_CMP3控制占空比,对应D6引脚(22)
     **
     ** 红外信号(left)   ------------>  D0
     ** 红外信号(right)  ------------>  D1
     **
     ** 电机驱动模块      开发板
     ** IN1 ------------> D8
     ** IN2 ------------> D9
     ** IN3 ------------> D10
     ** IN4 ------------> D11
     ** ENA ------------> D3_SCL
     ** ENB ------------> D4
     **
     **舵机信号线 ------------> D5
     **
     **超声波收发模块           开发板
     **引脚 Trig  ------------>  A0
     **引脚 Echo  ------------>  A1
     **引脚 Vcc   ------------>  5V VCC
     **引脚 Gnd   ------------>  GND
    **************************************************************/
    /**********************************************************************
    ** 程序修改记录:
    ** 2018-8-1
    ** 1、修改了hifive1.h内的智能车的宏定义,直接在主程序文件里面写了新的宏定义
    ** 2、备注了定时器内的模拟pwm波的代码,添加了硬件pwm代码
    ** 2018-8-7
    ** 1、程序目前可以实现循迹功能、超声波测距回显、超声波控制小车启停的功能
    ** 2、接下来需要添加一路PWM,控制舵机旋转 D5引脚输出控制舵机的PWM
    ** 2018-8-8
    ** 1、要求实现的功能:
    **当小车靠近墙壁的时候,超声波检测到距离过近,停止小车前进,测量左边和右边的距离,比较两者,选择向距离大的一边转弯。
    **需要添加的代码:
    **(1)左转弯90度(2)右转弯90度(3)当小车靠近墙壁的时候,对多舵机和超声波以及直流电机的组合操作
    **2、设计程序
    **3、添加了void motor_right()、void motor_left()、void motor_stop()函数。并且测试完毕,可以实现90度的转弯
    **4、添加了void ultrasonic_control()函数,内部的逻辑编写完毕,等待配件到达后组装测试
    ***********************************************************************/
    //========================== smart-car-gpio===========================//
    #define	run	1
    #define stop 0
    #define	left_monitor	D0_RX1
    #define	right_monitor	D1_TX1
    
    #define	car_motor_IN1		D8
    #define	car_motor_IN2		D9
    #define	car_motor_IN3		D10
    #define	car_motor_IN4		D11
    
    #define car_motor_ENA		D3_SCL
    #define	car_motor_ENB		D4
    
    #define servo_motor			D5//控制舵机 输出PWM的引脚
    //2018-8-7
    #define servo_motor_right		PWM1_REG(PWM_CMP2)  = 0xffff/1000*125;  // PWM高电平为0.5ms 舵机为0度
    #define servo_motor_middle		PWM1_REG(PWM_CMP2)  = 0xffff/1000*125*3;// PWM高电平为1.5ms 舵机为90度
    #define servo_motor_left		PWM1_REG(PWM_CMP2)  = 0xffff/1000*125*5;// PWM高电平为2.5ms 舵机为180度
    //2018-8-8
    #define left_monitor_run_fast    PWM1_REG(PWM_CMP1) = 0xffff/9*4 // 4/9 PWM
    #define right_monitor_run_fast   PWM1_REG(PWM_CMP0) = 0xffff/9*4 // 4/9 PWM
    
    #define left_monitor_run    PWM1_REG(PWM_CMP1) = 0xffff/9*2 // 2/9 PWM
    #define right_monitor_run   PWM1_REG(PWM_CMP0) = 0xffff/9*2 // 2/9 PWM
    #define left_monitor_stop   PWM1_REG(PWM_CMP1) = 0
    #define right_monitor_stop  PWM1_REG(PWM_CMP0) = 0
    //===================================================================//
    
    #include <stdio.h>
    #include <stdlib.h>
    #include "platform.h"
    #include <string.h>
    #include "plic/plic_driver.h"
    #include "encoding.h"
    #include <unistd.h>
    #include "stdatomic.h"
    
    void reset_demo (void);
    uint32_t GPIO_SET(uint32_t pin_num,uint32_t pin_val,uint32_t pin_model);
    void smartcar_init(void);
    void tracking_car_control(void);
    uint32_t read_pin_val(uint32_t pin_num);
    int delay_us(uint32_t time_x);
    void PWM_init();
    volatile void wait_ms(uint64_t ms);
    float ultrasonic(void);
    void ultrasonic_control();
    void motor_right();
    void motor_left();
    void motor_run();
    void motor_stop();
    void motor_back();
    void motor_forward();
    
    
    volatile int ultrasonic_run = 1;//超声波检测标志
    
    //=================================================================
    // Structures for registering different interrupt handlers
    // for different parts of the application.
    typedef void (*function_ptr_t) (void);
    void no_interrupt_handler (void) {};
    function_ptr_t g_ext_interrupt_handlers[PLIC_NUM_INTERRUPTS];
    // Instance data for the PLIC.
    plic_instance_t g_plic;
    
    //******************************************************************
    //函数名:  wait_ms()
    //作者:    Alvin Xu of PerfXLab
    //日期:    2018-08-01
    //功能:    调用一次产生ms毫秒的软件延时
    //输入参数:ms :毫秒数
    //返回值:  无
    //修改记录:无
    //******************************************************************
    volatile void wait_ms(uint64_t ms)//busy wait for the specified time
    {
      static const uint64_t ms_tick = RTC_FREQ/1000;
      volatile uint64_t * mtime  = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME);
      uint64_t then = (ms_tick * ms) + *mtime;
      while(*mtime<then);
    }
    
    
    
    //******************************************************************
    //函数名:  reset_demo
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:    定时器初始化程序
    //输入参数:无
    //返回值:  无
    //修改记录:无
    //******************************************************************
    void reset_demo ()
    {
      // Disable the machine & timer interrupts until setup is done.
      clear_csr(mie, MIP_MEIP);
      clear_csr(mie, MIP_MTIP);
    
      for (int ii = 0; ii < PLIC_NUM_INTERRUPTS; ii ++)
      {
        g_ext_interrupt_handlers[ii] = no_interrupt_handler;
      }
        // Set the machine timer to go off in 0.01 seconds.
        // The
        volatile uint64_t * mtime       = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME);
        volatile uint64_t * mtimecmp    = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
        uint64_t now = *mtime;
        uint64_t then = now + 0.1*RTC_FREQ;
        *mtimecmp = then;
    
        // Enable the Machine-External bit in MIE
        set_csr(mie, MIP_MEIP);
    
        // Enable the Machine-Timer bit in MIE
        set_csr(mie, MIP_MTIP);
    
        // Enable interrupts in general.
        set_csr(mstatus, MSTATUS_MIE);
    }
    
    //******************************************************************
    //函数名:  GPIO_SET
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:    配置蜂鸟的引脚
    //输入参数:pin_num:引脚名
    //			pin_val:引脚值,1或0
    //			pin_model:引脚模式,写input表示输入,写output表示输出
    //返回值:  无
    //修改记录:无
    //******************************************************************
    uint32_t GPIO_SET(uint32_t pin_num,uint32_t pin_val,uint32_t pin_model)
    {
        uint32_t input_val;
        if(pin_model==output)
         {
    	    GPIO_REG(GPIO_OUTPUT_EN) |= (0x01<<pin_num);
            if(pin_val==1)
    		{
    	     GPIO_REG(GPIO_OUTPUT_VAL) |=(0x01<<pin_num);
    		}
            if(pin_val==0)
    		{
    	     GPIO_REG(GPIO_OUTPUT_VAL) &=~(0x01<<pin_num);
    		}
        }
        if(pin_model==input)
        {
    	GPIO_REG(GPIO_INPUT_EN) |= (0x01<<pin_num);
    
    
    		input_val=GPIO_REG(GPIO_INPUT_VAL) &(0x01<<pin_num);
    		if(input_val!=0)
    		{
    			input_val=1;
    		}else
    		{
    			input_val=0;
    		}
    		return	input_val;
        }
     return 0;
    }
    
    //******************************************************************
    //函数名:  smartcar_control
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:   小车控制函数。实现小车的自动寻迹功能
    //输入参数:无
    //返回值:  无
    //修改记录:无
    //******************************************************************
    void tracking_car_control()
    {
    	uint32_t left_val,right_val;
    
    	left_val=read_pin_val(left_monitor);//读取左边寻迹模块的检测信号
    	right_val=read_pin_val(right_monitor);//读取右边寻迹模块的检测信号
    
    	if(left_val==1)
    	{
    		right_monitor_run;//使能右边电机
    	}
    	if(right_val==1)
    	{
    		left_monitor_run;	//使能左边电机
    	}
    	if(left_val==0)
    	{
    		right_monitor_stop;//失能右边电机
    	}
    	if(right_val==0)
    	{
    		left_monitor_stop;//失能左边电机
    	}
    	/*if(ultrasonic_run == 0)
    	{
    		motor_stop();
    	}*/
    
    }
    //******************************************************************
    //函数名:  motor_stop
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:   关闭小车的两个电机
    //输入参数:无
    //返回值:  无
    //修改记录:无
    //******************************************************************
    void motor_stop()
    {
    	right_monitor_stop;
    	left_monitor_stop;
    }
    //******************************************************************
    //函数名:  motor_run
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:   启动小车的两个电机
    //输入参数:无
    //返回值:  无
    //修改记录:无
    //******************************************************************
    void motor_run()
    {
    	right_monitor_run;
    	left_monitor_run;
    }
    
    //******************************************************************
    //函数名:  motor_forward
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:   实现小车车轮向后转
    //输入参数:无
    //返回值:  无
    //修改记录:无
    //******************************************************************
    void motor_forward()
    //可以通过修改延时时间或者输出pwm波的占空比来调整转弯的角度
    //目前调用一次可以原地 向左 旋转90度左右
    {
    	//左轮前转
    	GPIO_SET(car_motor_IN1		,0,output);
    	GPIO_SET(car_motor_IN2		,1,output);
    	//右轮前转
    	GPIO_SET(car_motor_IN3		,0,output);
    	GPIO_SET(car_motor_IN4		,1,output);
    
    	motor_run();
    }
    
    //******************************************************************
    //函数名:  motor_back
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:   实现小车车轮向后转
    //输入参数:无
    //返回值:  无
    //修改记录:无
    //******************************************************************
    void motor_back()
    {
    	//左轮后转
    	GPIO_SET(car_motor_IN1		,1,output);
    	GPIO_SET(car_motor_IN2		,0,output);
    	//右轮后转
    	GPIO_SET(car_motor_IN3		,1,output);
    	GPIO_SET(car_motor_IN4		,0,output);
    
    	motor_run();
    }
    //******************************************************************
    //函数名:  motor_left
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:   可以通过修改延时时间或者输出pwm波的占空比来调整转弯的角度
    //     目前调用一次可以原地 向左 旋转90度左右
    //输入参数:无
    //返回值:  无
    //修改记录:无
    //******************************************************************
    void motor_left()
    {
    	//左轮后转
    	GPIO_SET(car_motor_IN1		,1,output);
    	GPIO_SET(car_motor_IN2		,0,output);
    	//右轮前转
    	GPIO_SET(car_motor_IN3		,0,output);
    	GPIO_SET(car_motor_IN4		,1,output);
    
    	right_monitor_run_fast;
    	left_monitor_run_fast;
    	wait_ms(300);
    	motor_stop();
    }
    
    //******************************************************************
    //函数名:  motor_right
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:   可以通过修改延时时间或者输出pwm波的占空比来调整转弯的角度
    //		目前调用一次可以原地 向右 旋转90度左右
    //输入参数:无
    //返回值:  无
    //修改记录:无
    //******************************************************************
    void motor_right()
    
    {
    	//左轮前转
    	GPIO_SET(car_motor_IN1		,0,output);
    	GPIO_SET(car_motor_IN2		,1,output);
    	//右轮后转
    	GPIO_SET(car_motor_IN3		,1,output);
    	GPIO_SET(car_motor_IN4		,0,output);
    
    	right_monitor_run_fast;
    	left_monitor_run_fast;
    	wait_ms(300);
    	motor_stop();
    }
    
    //******************************************************************
    //函数名:  ultrasonic
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:   实现 超声波测距功能,并将距离返回到Serial Terminal
    //输入参数:无
    //返回值:  distance
    //修改记录:无
    //******************************************************************
    float distance=0;
    float ultrasonic()
    {
    	uint64_t t1=0,t2=0;
    
    	GPIO_SET(A1,0,input);//将A1配置为输入,接收超声波输入信号
    	GPIO_SET(A0,1,output);
    	delay_us(1);//触发超声测距模块,产生12.4us的电平
    	GPIO_SET(A0,0,output);
    
    	while( read_pin_val(A1) == 0 );	//A1输入为0时等待
    	t1 = get_timer_value();
    	while( read_pin_val(A1) == 1 );//A1输入为1时计数,测量高电平长度
       	t2 = get_timer_value();
       	distance =( (float)(t2-t1) )/RTC_FREQ*340/2;
    
    	printf("%.2f厘米   \n \n",distance*100);//将测得的距离回传到Terminal里面显示
    
    	wait_ms(80);
    
    	return distance;
    }
    //******************************************************************
    //函数名:  ultrasonic_control
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:    超声波避障功能的控制逻辑
    //输入参数:无
    //返回值:  无
    //修改记录:无
    //******************************************************************
    void ultrasonic_control()
    {
    	ultrasonic();//触发超声波模块,并测量距离,给标志位置位(用led显示状态)
    
    	float distance_left = 0, distance_right = 0;
    	if( distance < 0.15   )//小于0.15米,停车
    	{
    		motor_stop();//停车
    		GPIO_SET(ledD3,1,output);
    
    		servo_motor_left;
    		wait_ms(500);
    		distance_left = ultrasonic();
    		wait_ms(500);
    		servo_motor_right;
    		wait_ms(500);
    		distance_right = ultrasonic();
    		wait_ms(500);
    		servo_motor_middle;
    
    		if(distance_left >= distance_right)
    			motor_left();
    		else
    			motor_right();
    
    		motor_forward();
    
    
    	}
    	else
    	{
    		GPIO_SET(ledD3,0,output);
    		motor_run();
    	}
    }
    
    //******************************************************************
    //函数名:  PWM_init
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:    PWM功能的寄存器配置和初始化
    //输入参数:无
    //返回值:  无
    //修改记录:无
    //******************************************************************
    void PWM_init()
    {
    	  //初始化PWM1寄存器为全0
    	  PWM1_REG(PWM_CFG)   = 0;
    	  //使能PWM1的4路PWM波  |  避免毛刺	| 计数器清零	|  配置计数器分频系数
    	  PWM1_REG(PWM_CFG)   = (PWM_CFG_ENALWAYS| PWM_CFG_DEGLITCH | PWM_CFG_ZEROCMP | 0xA);
    	  //
    	  PWM1_REG(PWM_COUNT) = 0;
    	  //选择IOF模式为IOF1
    	  GPIO_REG(GPIO_IOF_SEL)  |= ( (1 << car_motor_ENA) | (1 << car_motor_ENB) | (1 << servo_motor) );
    	  //IOF使能,使io口可以输出PWM波
    	  GPIO_REG(GPIO_IOF_EN )  |= (1 << car_motor_ENA) ;
    	  GPIO_REG(GPIO_IOF_EN )  |= (1 << car_motor_ENB);
    	  GPIO_REG(GPIO_IOF_EN )  |= (1 << servo_motor);
    	  //输出取反
    	  GPIO_REG(GPIO_OUTPUT_XOR)|= ( (1 << car_motor_ENA) | (1 << car_motor_ENB) | (1 << servo_motor) );
    	  //配置占空比
    	  PWM1_REG(PWM_CMP0)  = 0;//0% PWM  一个周期的时钟个数(分频后) 160000
    	  PWM1_REG(PWM_CMP1)  = 0;//0% PWM 0xffff/5
    	  PWM1_REG(PWM_CMP2)  = 0;//0% PWM高电平为5ms
    
    	  //配置输出频率为 244/8 Hz,频率最小可以到 244/(2^15) Hz
    	  //PWM1_REG(PWM_CFG) |= 0;//为原频率的 2的0次方 分之一
    }
    
    //******************************************************************
    //函数名:  smartcar_init
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:    小车Io口的初始化
    //输入参数:无
    //返回值:  无
    //修改记录:无
    //******************************************************************
    void smartcar_init()
    {
    	//超声距离检测指示端口灯初始化
    	GPIO_SET(ledD3,1,output);
    
    	//初始化红外模块输出信号的接收端口
    	GPIO_SET(left_monitor	,0,input);
    	GPIO_SET(right_monitor	,0,input);
    
    	//确定电机方向向前行
    	GPIO_SET(car_motor_IN3		,0,output);
    	GPIO_SET(car_motor_IN4		,1,output);
    	GPIO_SET(car_motor_IN1		,0,output);
    	GPIO_SET(car_motor_IN2		,1,output);
    }
    //******************************************************************
    //函数名:  read_pin_val
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:    读输入引脚的电平
    //输入参数:pin_num
    //返回值:  1或0
    //修改记录:无
    //******************************************************************
    uint32_t read_pin_val(uint32_t pin_num)
    {
    	if((GPIO_REG(GPIO_INPUT_VAL))&(0x01<<pin_num))
    	{
    		return 1;
    	}
    	else
    		return 0;
    }
    //******************************************************************
    //函数名:  delay_us
    //作者:    PerfXLab
    //日期:    2018-07-04
    //功能:    time_x = 1 时产生12.4us的延时
    //输入参数:time_x
    //返回值:  无
    //修改记录:无
    //******************************************************************
    int delay_us(uint32_t time_x)//time_x = 1 时产生12.4us的延时
    {
    	volatile uint32_t num;
    //注意不要将volatile语句删除,否则编译器会自动优化掉延时函数,导致延时函数无法工作
    	num = 25*time_x;
    	while(num>0)
    		{num--;}
    return 0;
    }
    
    //==============以下两个函数是中断函数接口=====================================//
    /*Entry Point for PLIC Interrupt Handler*/
    void handle_m_ext_interrupt()
    {
      plic_source int_num  = PLIC_claim_interrupt(&g_plic);
      if ((int_num >=1 ) && (int_num < PLIC_NUM_INTERRUPTS))
      {
        g_ext_interrupt_handlers[int_num]();
      }
      else
      {
        exit(1 + (uintptr_t) int_num);
      }
      PLIC_complete_interrupt(&g_plic, int_num);
    }
    /*Entry Point for Machine Timer Interrupt Handler*/
    void handle_m_time_interrupt()
    {
    	clear_csr(mie, MIP_MTIP);
    
    	volatile uint64_t * mtime       = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIME);
    	volatile uint64_t * mtimecmp    = (uint64_t*) (CLINT_CTRL_ADDR + CLINT_MTIMECMP);
    	uint64_t now = *mtime;
    	uint64_t then = now +0.1*RTC_FREQ;
    	*mtimecmp = then;
    
    	//ultrasonic();
    
    	// Re-enable the timer interrupt.
    	set_csr(mie, MIP_MTIP);
    }
    //============================================================================//
    
    
    //============================================================================//
    //	主函数
    //=============================================================================//
    int main(int argc, char **argv)
    {
    
      /**************************************************************************
       * Set up the PLIC
       *************************************************************************/
       PLIC_init(&g_plic,
     	    PLIC_CTRL_ADDR,
     	    PLIC_NUM_INTERRUPTS,
     	    PLIC_NUM_PRIORITIES);
    
       GPIO_SET(ledD3,1,output);	//测试端口初始化
       smartcar_init();             //初始化相关端口
       PWM_init();    				//初始化PWM1
       servo_motor_middle;			//控制舵机使超声波模块面向向前方
       motor_forward();				//使能直流电机,小车前进
       while (1)
    	{
    		//两种功能可以选择使用
    		//方法是备注掉不用的那一行代码
    		
    	    ultrasonic_control();	//超声波避障功能
    	   // tracking_car_control();  //循迹小车功能
    
    	}
    
    }
    
    


  • 请问您用的是哪个ip核!?



  • @yclylyf 使用的x-core ip,还是蜂鸟e200?


Log in to reply