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代码
/*************************************************
\\file main.c
\\brief main function for test demo
\\version V0.1, 2023-10-28, firmware for CSM32RV003
在原厂资料改003_reset_EN.zip的基础上改写
程序功能: PA3外接按键,设置为下拉,接电源时按键触发。
开机白色LED亮2s,然后红、绿、蓝三色LED按150ms间隔循环闪烁,
由于设置了timer1中断,500ms中断触发一次,所以PA6接的黄LED按500ms规律闪烁。
当PA3按键按了一下后,红、绿、蓝三色LED按800ms间隔循环闪烁10次,然后恢复到
主程序运行状态:红、绿、蓝三色LED按100ms间隔循环闪烁。
********************************************************/
/*************************************************
\\file main.c
\\brief main function for test demo
\\version V0.1, 2023-10-28, firmware for CSM32RV003
在原厂资料改003_reset_EN.zip的基础上改写
程序功能:
PA3外接按键,设置为下拉,接电源时按键触发。
开机白色LED亮2s,然后红、绿、蓝三色LED按150ms间隔循环闪烁,
由于设置了timer1中断,500ms中断触发一次,所以PA6接的黄LED按500ms规律闪烁。
当PA3按键按了一下后,红、绿、蓝三色LED按800ms间隔循环闪烁10次,然后恢复到
主程序运行状态:红、绿、蓝三色LED按100ms间隔循环闪烁。
********************************************************/
#include "headfile.h"
#define KEY_PA3 PIN3 //按键位置
#define LED_B_PA8 PIN8 //蓝B_LED 位置 LED_B__PA8 LED_G__PA9 LED_R__PA12
#define LED_G_PA9 PIN9 //绿G_LED 位置
#define LED_R_PA12 PIN12 //红R_LED 位置
#define LED_Y_PA6 PIN6 //黄Y_LED 位置
#define SFT ((SFT_TypeDef *)SFT_BASE)
#define SFT_BASE 0x30000360UL
volatile uint32_t NRST_EN;
/********************************
//根据timer.c修改 参考https://bbs.elecfans.com/jishu_2241443_1_1.html
//修改要在timer.c中进行 !!!!!!!!!!!!!!!!!!!!!!!
//该函数从timer.c中剪切来的
void Timer1_UpCounting_Mode_Init(void) //Timer1向上计数
{
TIMER1->CR1 = 0; //CR1[0]计数器开关:0-关闭,1-开启
TIMER_CLKEN->CLKEN |= 1; //CLKEN[8] Timer2时钟开关:1开启,0-关闭
//CLKEN[0] Timer1时钟开关:1开启,0-关闭
TIMER1->PSC = 32000-1; //预分频 32MHZ/1KHZ=32000,时钟1KHZ
TIMER1->ARR = 500-1; //自动重装寄存器 定时周期500ms
TIMER1->RCR = 0; //重复计数
TIMER1->IER = 1 << 0; //使能TIMER1中断:1-使能,0-关闭
}
*******************************************************************/
//有了如下的函数所以可以把中断函数的在此处修改
void Timer1_Update_IRQhandler(void) **attribute** ((interrupt("SiFive-CLIC-preemptible"))); //该函数在it.h中
void Timer1_Update_IRQhandler(void) //原函数在原厂的it.c中,要把it.c中的该函数注释掉
{
Timer1_Update_Isr();
}
void Timer1_Update_Isr(void) //更新 //该函数在原厂的timer.c中,要把它注释掉
{
if(TIMER1->SR&0x1)
{
TIMER1->SR &= ~0x1; //原厂的
//TIMER1->SR &= ~(0x1 << 0); //一样的
GPIO_Toggle(GPIOA,LED_Y_PA6 ); //黄灯闪烁,间隔500ms
}
}
int main(void)
{
typedef struct
{
volatile uint32_t EN;
volatile uint32_t NRST_EN;
}SFT_TypeDef;
SFT->NRST_EN=0; //使能MCU003PA15硬件复位@
///---- 系统总中断控制 -------------------------------------------------------------------------------------------------
//SYS_Interrupt_Enable();//CLIC开总中断
//SYS_Interrupt_Disable();//CLIC关总中断
//ee_printf("\\nHello CSM32RV20:");
//printf("Hello CSM32RV20:\\r\\n");
///----Chapter 5 GPIO Test Init ---------------------------------------------------------------------------------
//输出端口的设置
GPIO_MODE_Init(GPIOA,LED_B_PA8,GPIO_MODE_OUTPUT); //GPIO的PA8输出模式
GPIO_MODE_Init(GPIOA,LED_G_PA9 ,GPIO_MODE_OUTPUT); //端口初始化,PA9输出模式
GPIO_MODE_Init(GPIOA,LED_R_PA12,GPIO_MODE_OUTPUT); //GPIO的PA12输出模式
GPIO_MODE_Init(GPIOA,LED_Y_PA6,GPIO_MODE_OUTPUT); //GPIO的PA6输出模式
//为了驱动不同的负载,可以设置不同的输出方式
//GPIO_OutType_Init(GPIOA,PIN12,GPIO_OTYPE_ODOS_ON ); //PA12推免输出
//GPIO_OutType_Init(GPIOA,PIN12,GPIO_OTYPE_ODOS_OFF ); //PA12 关闭开漏、开源功能
//GPIO_OutType_Init(GPIOA,PIN12,GPIO_OTYPE_OS_ON ); //PA12开源输出
//GPIO_OutType_Init(GPIOA,PIN12, GPIO_OTYPE_ODOS_OFF); //PA12关闭开漏、开源功能
//GPIO_OutType_Init(GPIOB,PIN10, GPIO_OTYPE_ODOS_OFF); //PB10关闭开漏、开源功能
/***************************************************************/
//点亮开发板上的三基色2s
GPIO_Write(GPIOA, LED_G_PA9,GPIO_RESET); //GPIO的PA9输出0
//GPIO_Write(GPIOA,PIN9, SET); //GPIO的PA9输出1
GPIO_Write(GPIOA, LED_B_PA8 ,GPIO_RESET); //GPIO的PA8 输出0
GPIO_Write(GPIOA, LED_R_PA12,GPIO_RESET); //GPIO的PA12 输出0
Delay32M_ms(2000); //调用32MHZ系统的延时函数 延时2s
//熄灭开发板上的三基色
GPIO_Write(GPIOA, LED_B_PA8 ,GPIO_SET); //PA8输出1 PA8接Blue LED 低电平LED亮 关闭
GPIO_Write(GPIOA,LED_G_PA9,1); //PA9输出1 PA9接Green LED 低电平LED亮 关闭
GPIO_Write(GPIOA,LED_R_PA12,1); //PA12输出 PA9接RED LED 低电平LED亮 关闭
//输入口的设置
GPIO_InType_Init( GPIOA, KEY_PA3,GPIO_MODE_INPUT); //GPIO的PA3输入模式,外接按键
//GPIO_PULL_Init(GPIOA, KEY_PA3, GPIO_PULLUP); //PA3 上拉 未按下时是1
GPIO_PULL_Init(GPIOA, KEY_PA3, GPIO_PULLDOWN); // PA3下拉 未按下时是0
//GPIO_PULL_Init(GPIOA, KEY_PA3, 0GPIO_NOPULL ); // PA3浮空
//这里中断设置放LED及按键的后边,开机三个LED同时发光2s,然后中断动作
///---------- System Init ----------///
CLIC_Init();//系统中断配置
//SysClock_RC_Mode_Init(); //系统时钟初始化:RC模式
//SysClock_Crystal_Mode_Init(); //系统时钟初始化:晶振模式
//SysClock_PLL_Mode_Init(); //系统时钟初始化:PLL模式
SysClock_Test_Init(); //系统时钟初始化
Timer1_UpCounting_Mode_Init( ); //Timer1向上计数,有修改
Interrupt_Level(TIMER1_updata_int_ID,INT_LEVEL0); //CLIC设置中断抢占级别 优先级 lic.h中
Interrupt_Enable(TIMER1_updata_int_ID); //CLIC使能中断 允许Timer1溢出中断
//使能系统总中断
SYS_Interrupt_Enable( ); //CLIC开总中断
while(1)
{
//if( !GPIO_Read(GPIOA, PIN3) ) //GPIO输入上拉时 读输入为0表示按键按下
if( GPIO_Read(GPIOA, KEY_PA3) ) //GPIO输入下拉时 读输入为1表示按键按下
{
//自己加的代码
Delay32M_ms(20); //20ms消除抖动
while(GPIO_Read(GPIOA, KEY_PA3)) ; //等待按键抬起
while(!GPIO_Read(GPIOA, KEY_PA3)) ; //等待按键抬起
for(uint8_t i=0;i<10;i++) //3个LED依次闪烁10次
{
GPIO_Toggle(GPIOA,LED_R_PA12); //PA12翻转 开发板上PA12接Red LED
Delay32M_ms(800);
GPIO_Write(GPIOA,LED_R_PA12,GPIO_SET); //关闭红灯,消除余辉影响
GPIO_Toggle(GPIOA,LED_G_PA9); //PA9翻转 开发板上PA9接Green LED
Delay32M_ms(800);
GPIO_Write(GPIOA,LED_G_PA9,GPIO_SET); //PA9输出1 关闭绿灯 消除余辉影响
GPIO_Toggle(GPIOA,LED_B_PA8); //GPIO 翻转 开发板上PA8接Blue LED
Delay32M_ms(800);
GPIO_Write(GPIOA,LED_B_PA8,1); //PA8输出1 关闭蓝灯消除余辉影响
}
}
else //无按键按下,红、绿、蓝三色LED按间隔150ms闪烁
{
GPIO_Toggle(GPIOA,LED_R_PA12); //PA12翻转 开发板上PA12接Red LED
Delay32M_ms(100);
GPIO_Write(GPIOA,LED_R_PA12,GPIO_SET); //关闭红灯,消除余辉影响
GPIO_Toggle(GPIOA,LED_G_PA9); //PA9翻转 开发板上PA9接Green LED
Delay32M_ms(100);
GPIO_Write(GPIOA,LED_G_PA9,GPIO_SET); //PA9输出1 关闭绿灯 消除余辉影响
GPIO_Toggle(GPIOA,LED_B_PA8); //GPIO 翻转 开发板上PA8接Blue LED
Delay32M_ms(100);
GPIO_Write(GPIOA,LED_B_PA8,1); //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"))); //该函数在it.h中
void Timer1_Update_IRQhandler(void) //原函数在原厂的it.c中,要把it.c中的该函数注释掉
{
Timer1_Update_Isr();
}
void Timer1_Update_Isr(void) //更新 //该函数在原厂的timer.c中,要把它注释掉
{
if(TIMER1->SR&0x1)
{
TIMER1->SR &= ~0x1; //原厂的
//TIMER1->SR &= ~(0x1 << 0); //一样的
GPIO_Toggle(GPIOA,LED_Y_PA6 ); //黄灯闪烁,间隔500ms
}
}
后面的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文件都起什么作用,希望有大侠可以解释一下。
更多回帖