1、前言
申请的CSM32RV003开发板研究好长一段时间了,但是还有不少问题需要解决,一点一点的啃,终于把I/O口和timer1溢出中断弄得差不多了,这里感谢南京中科微的工程师和微信群的好友的帮助。
2、程序功能:
PA3外接按键,设置为下拉,接电源时按键触发。
开机白色LED亮2s,然后红、绿、蓝三色LED按150ms间隔循环闪烁,
由于设置了timer1中断,500ms中断触发一次,所以PA6接的黄LED按500ms规律闪烁。
当PA3按键按了一下后,红、绿、蓝三色LED按800ms间隔循环闪烁10次,然后恢复到
主程序运行状态:红、绿、蓝三色LED按100ms间隔循环闪烁。
3、代码
这里贴出了main.c代码
#include "headfile.h"
#define KEY_PA3 PIN3
#define LED_B_PA8 PIN8
#define LED_G_PA9 PIN9
#define LED_R_PA12 PIN12
#define LED_Y_PA6 PIN6
#define SFT ((SFT_TypeDef *)SFT_BASE)
#define SFT_BASE 0x30000360UL
volatile uint32_t NRST_EN;
void Timer1_Update_IRQhandler(void) **attribute** ((interrupt("SiFive-CLIC-preemptible")));
void Timer1_Update_IRQhandler(void)
{
Timer1_Update_Isr();
}
void Timer1_Update_Isr(void)
{
if(TIMER1->SR&0x1)
{
TIMER1->SR &= ~0x1;
GPIO_Toggle(GPIOA,LED_Y_PA6 );
}
}
int main(void)
{
typedef struct
{
volatile uint32_t EN;
volatile uint32_t NRST_EN;
}SFT_TypeDef;
SFT->NRST_EN=0;
GPIO_MODE_Init(GPIOA,LED_B_PA8,GPIO_MODE_OUTPUT);
GPIO_MODE_Init(GPIOA,LED_G_PA9 ,GPIO_MODE_OUTPUT);
GPIO_MODE_Init(GPIOA,LED_R_PA12,GPIO_MODE_OUTPUT);
GPIO_MODE_Init(GPIOA,LED_Y_PA6,GPIO_MODE_OUTPUT);
GPIO_Write(GPIOA, LED_G_PA9,GPIO_RESET);
GPIO_Write(GPIOA, LED_B_PA8 ,GPIO_RESET);
GPIO_Write(GPIOA, LED_R_PA12,GPIO_RESET);
Delay32M_ms(2000);
GPIO_Write(GPIOA, LED_B_PA8 ,GPIO_SET);
GPIO_Write(GPIOA,LED_G_PA9,1);
GPIO_Write(GPIOA,LED_R_PA12,1);
GPIO_InType_Init( GPIOA, KEY_PA3,GPIO_MODE_INPUT);
GPIO_PULL_Init(GPIOA, KEY_PA3, GPIO_PULLDOWN);
CLIC_Init();
SysClock_Test_Init();
Timer1_UpCounting_Mode_Init( );
Interrupt_Level(TIMER1_updata_int_ID,INT_LEVEL0);
Interrupt_Enable(TIMER1_updata_int_ID);
SYS_Interrupt_Enable( );
while(1)
{
if( GPIO_Read(GPIOA, KEY_PA3) )
{
Delay32M_ms(20);
while(GPIO_Read(GPIOA, KEY_PA3)) ;
while(!GPIO_Read(GPIOA, KEY_PA3)) ;
for(uint8_t i=0;i<10;i++)
{
GPIO_Toggle(GPIOA,LED_R_PA12);
Delay32M_ms(800);
GPIO_Write(GPIOA,LED_R_PA12,GPIO_SET);
GPIO_Toggle(GPIOA,LED_G_PA9);
Delay32M_ms(800);
GPIO_Write(GPIOA,LED_G_PA9,GPIO_SET);
GPIO_Toggle(GPIOA,LED_B_PA8);
Delay32M_ms(800);
GPIO_Write(GPIOA,LED_B_PA8,1);
}
}
else
{
GPIO_Toggle(GPIOA,LED_R_PA12);
Delay32M_ms(100);
GPIO_Write(GPIOA,LED_R_PA12,GPIO_SET);
GPIO_Toggle(GPIOA,LED_G_PA9);
Delay32M_ms(100);
GPIO_Write(GPIOA,LED_G_PA9,GPIO_SET);
GPIO_Toggle(GPIOA,LED_B_PA8);
Delay32M_ms(100);
GPIO_Write(GPIOA,LED_B_PA8,1);
}
}
return 0;
}
- 经验
(1)关于原厂无参库函数(非中断函数)的修改
一定要在原函数所在的*.c文件中修改,函数头不可改动,大括号里的内容可以改动,为了与原厂内容有所区分,最好把原厂内容注释掉。当然为了便于看,可以把修改后的函数复制粘贴到main.c中再注释掉。如本例的void Timer1_UpCounting_Mode_Init(void) //Timer1
向上计数
函数,大家可以查看main.c和timer.c文件。
有参函数的内容一般不需改动,我们在调用时只需修改参数即可。
(2)中断函数的修改
由于中断函数的内容一般要用户填写,所以要修改,该开源开发板又不同于普通的8位单片机,他的操作有类似于原厂无参库函数(非中断函数)的修改,修改方法以timer1
为例。要在main.c中插入如下代码:
void Timer1_Update_IRQhandler(void) __attribute__((interrupt("SiFive-CLIC-preemptible")));
void Timer1_Update_IRQhandler(void)
{
Timer1_Update_Isr();
}
void Timer1_Update_Isr(void)
{
if(TIMER1->SR&0x1)
{
TIMER1->SR &= ~0x1;
GPIO_Toggle(GPIOA,LED_Y_PA6 );
}
}
后面的2个函数要在相应的*.c文件中注释掉。
(3)关于ISP下载
ISP下载提示复位时,最好一直按住复位键直到下载结束。若果ISP下载失败,可以在编译软件的maicn.c窗口,cjlink一端连电脑,另一端亮开发板,点击菜单烧录/下载,用cjlink也可以,成功后再用ISP下载。
5、问题
void Timer1_Update_IRQhandler(void) **attribute** ((interrupt("SiFive-CLIC-preemptible")));
//该函数看不懂,它在it.h中的作用,以及it.h和it.c文件都起什么作用,希望有大侠可以解释一下。