这次有幸收到了CH32V307评估板,拿到第一时间,开箱,再点灯。
一、开箱:
沁恒的板子,包装一如既往的比较简洁,和小弟103在一起:
两者的说明书,完全一样,除了名字:
再来看一看正面:
和103一样,自带WCH-LINK,对于开发者非常方便,接上就可以调试了。
板子上,带有可以独立控制的两个LED,两个按钮(1个RESET,1个USER可控制的),两个type-C口,后有一个有线网口。
另外,接口是Arduino兼容的,可以把Arduino扩展板直接接上使用。
然后,再看看反面:
最后再来一张冲击照:
看完板子,就是点灯。
二、官方GPIO点灯实例
我们先来看看沁恒提供的例子,真的是非常的丰富,方方面面的全都有了,对学习者非常的友好。
在上面的例子中,我是一眼就看到了HarmonyOS,下面要做的,就是跑HarmonyOS,并结合GPIO实例,在HarmonyOS点灯。
首先,要下载专用的开发工具 MounRiver Studio,下载地址为:
选择 集成开发环境 即可。熟悉Eclipse的同学,可以选择社区版。
下载后,完成安装,就可以到示例目录中,项目名.wvproj,就能直接打开例子项目了。
MounRiver Studio的使用,请大家查看官方的资料《CH32V30x评估板说明书.pdf》,这里就不多说了。
因为要点灯,所以我们先打开GPIO/GPIO_Toggle项目,具体如下:
在上述代码中,GPIO_Toggle_INIT
进行初始化,GPIO_WriteBit
负责设置对应GPIO端口的输出。
要正确点灯,我们需要从原理图上,先了解LED的线路。
在CH32V307评估板上,通过原理图,我们可以了解到,可以使用的Pin如下:
从其中可以看到,CH32V307的引脚,是分组为PA、PB、PC、PD的。
看板子正面,会更清晰:
板子上的两个LED 的威廉希尔官方网站 如下:
这两个LED是独立的,可以通过跳线,连接到任意的GPIO端口,进行控制。
方便起见,我把LED1连接到了PA0,LED2连接到了PA1,具体如下:
(感谢lingxin-yuhe指出原图错误,已修正)
从GPIO/GPIO_Toggle的GPIO_Toggle_INIT
中,我们看到,对PA0进行了初始化,驱动连接到PA0的LED,那后面,我们就会对PA0、PA1初始化,从而驱动两个LED。
把LED1连接到PA0以后,编译源码,然后下载,LED1就会快速闪动了。
MounRiver Studio的按钮导航栏如下:
其中红框框起来的部分:
绿色单下箭头:表示编译
绿色双下箭头:重新编译
白色单下箭头:表示下载编译后的HEX到开发板
绿色虫子:表示debug调试,可以断点运行
下载前,应该先点下载旁边的小箭头,打开下载配置界面:
要下载代码,应确保点击放大镜图标,查看已经处于解锁图标。
三、HarmonyOS点双灯:
直接点击HarmonyOS/LiteOS_m/LiteOS_m.wvproj,就可以打开HarmonyOS项目,并参考GPIO/GPIO_Toggle进行修改,代码如下:
上述代码中,对PA0和PA1进行了初始化。
上述为main部分,添加了GPIO_Toggle_INIT()
调用。
在原有的两个task部分,分别切换PA0、PA1的状态,从而控制LED1、LED2的亮灭。
实际的连线如下:
最终的代码如下:
#include "los_tick.h"
#include "los_task.h"
#include "los_config.h"
#include "los_interrupt.h"
#include "los_debug.h"
#include "los_compiler.h"
/* Global define */
/* Global Variable */
attribute((aligned (8))) UINT8 g_memStart[LOSCFG_SYS_HEAP_SIZE];
UINT32 g_VlaueSp=0;
// LED状态
u8 led_status = 0;
u8 led_status2 = 0;
/*********************************************************************
@fn GPIO_Toggle_INIT
[url=home.php?mod=space&uid=2666770]@Brief[/url] 初始化 GPIOA.0、GPIOA.1
[url=home.php?mod=space&uid=1141835]@Return[/url] none
*/
void GPIO_Toggle_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
GPIO_InitTypeDef GPIO_InitStructure2 = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure2.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure2.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure2.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure2);
}
/*********************************************************************
@fn taskSampleEntry2
@brief taskSampleEntry2 program.
@return none
*/
VOID taskSampleEntry2(VOID)
{
while(1) {
LOS_TaskDelay(2000);
printf("taskSampleEntry2 running,task2 SP:xn",__get_SP());
GPIO_WriteBit(GPIOA, GPIO_Pin_1, (led_status2 == 0) ? (led_status2 = Bit_SET) : (led_status2 = Bit_RESET));
}
}
/*********************************************************************
@fn taskSampleEntry1
@brief taskSampleEntry1 program.
@return none
*/
VOID taskSampleEntry1(VOID)
{
while(1) {
LOS_TaskDelay(1000);
printf("taskSampleEntry1 running,task1 SP:xn",__get_SP());
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (led_status == 0) ? (led_status = Bit_SET) : (led_status = Bit_RESET));
}
}
/*********************************************************************
@fn EXTI0_INT_INIT
@brief Initializes EXTI0 collection.
@return none
*/
void EXTI0_INT_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure={0};
GPIO_InitTypeDef GPIO_InitStructure2={0};
EXTI_InitTypeDef EXTI_InitStructure={0};
NVIC_InitTypeDef NVIC_InitStructure={0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure2.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure2.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure2);
/* GPIOA ----> EXTI_Line0 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line=EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/*********************************************************************
@fn taskSample
@brief taskSample program.
@return none
/
UINT32 taskSample(VOID)
{
UINT32 uwRet;
UINT32 taskID1,taskID2;
TSK_INIT_PARAM_S stTask={0};
stTask.pfnTaskEntry = (TSK_ENTRY_FUNC)taskSampleEntry1;
stTask.uwStackSize = 0X500;
stTask.pcName = "taskSampleEntry1";
stTask.usTaskPrio = 6;/ 高优先级 */
uwRet = LOS_TaskCreate(&taskID1, &stTask);
if (uwRet != LOS_OK) {
printf("create task1 failedn");
}
stTask.pfnTaskEntry = (TSK_ENTRY_FUNC)taskSampleEntry2;
stTask.uwStackSize = 0X500;
stTask.pcName = "taskSampleEntry2";
stTask.usTaskPrio = 7;/* 低优先级 */
uwRet = LOS_TaskCreate(&taskID2, &stTask);
if (uwRet != LOS_OK) {
printf("create task2 failedn");
}
EXTI0_INT_INIT();
return LOS_OK;
}
/*********************************************************************
@fn main
@brief Main program.
@return none
*/
LITE_OS_SEC_TEXT_INIT int main(void)
{
unsigned int ret;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
Delay_Init();
USART_Printf_Init(115200);
printf("SystemClk:%drn",SystemCoreClock);
GPIO_Toggle_INIT();
ret = LOS_KernelInit();
taskSample();
if (ret == LOS_OK)
{
LOS_Start();
}
while (1) {
__asm volatile("nop");
}
}
/*********************************************************************
@fn EXTI0_IRQHandler
@brief This function handles EXTI0 Handler.
@return none
/
void EXTI0_IRQHandler(void) attribute((interrupt("WCH-Interrupt-fast")));
void EXTI0_IRQHandler(void)
{
/ 中断栈使用的是原来调用main设置的值,将中断栈和线程栈分开,这样线程跳中断,中断函数如果嵌套深度较大,不至于
线程栈被压满溢出,但是采用当前方式,线程进中断时,编译器保存到的16个caller寄存器任然压入线程栈,如果需要希
望caller寄存器压入中断栈,则中断函数的入口和出口需要使用汇编,中间调用用户中断处理函数即可,详见los_exc.S
中的ipq_entry例子
*/
GET_INT_SP();
HalIntEnter();
if(EXTI_GetITStatus(EXTI_Line0)!=RESET)
{
g_VlaueSp= __get_SP();
printf("Run at EXTI:");
printf("interruption sp:xrn",g_VlaueSp);
HalDisplayTaskInfo();
EXTI_ClearITPendingBit(EXTI_Line0); /* Clear Flag */
}
HalIntExit();
FREE_INT_SP();
}
编译下载后,两个LED,就会分别以自己的周期,进行亮灭了,如视频中所示。
更多回帖