关于PLIC中断
-
我使用的开发板为35T,内核为perfxlab的risc-v内核。请问如何通过GPIO调用button k1~k4实现硬件(外部)中断。
-
@yclylyf 网盘提供的压缩包是蜂鸟e203的
-
-
没有与你要求相同的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?