Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
内核学习营
《内核学习营》+水一方+项目中使用GPIO外设实现输入输出
发布于 2018-09-12 14:10:39 浏览:1789
订阅该版
* 本帖最后由 吉帅虎 于 2018-9-12 15:49 编辑 * 通过前面的学习。已经可以使用env工具简单的配置标准工程。并根据自己的项目创建了标准工程,接下来的实验都是在此标准工程的基础上进行的,同时根据自己板卡的具体应用,安装需求进行外设的实验。********************************************************************************************* 硬件:自用STM32F103VCT6板卡 实验目的:实现GPIO的输入输出控制,并根据项目需求完成功能。主要实现LED闪烁,继电器输出、按键输入控制 扩展功能:1、使用shell命令控制继电器输出 2、使用env配置输入输出所用的管脚 软件平台:env_released_1.0.0 ,mdk5.23 ********************************************************************************************* 第一步:实现LED闪烁 在移植标准工程的时候,BSP里带了LED闪烁的例子,只需要针对硬件更改对应的管脚即可。由于后续功能都是对GPIO的操作,故这一部分的代码没有进行调整,只修改了管脚号。 我用的BSP是STM32F10x的,BSP里用的是STD库。如下图 ![TIM图片20180912115413.png](/uploads/201809/12/115534l413t0z3xifow6qf.png) 代码内容也是按照STD库里的格式写的。由于是用的BSP里的源文件,代码就不贴了,大家都有。 第二步 按键输入 按照RT-Thread的分层,外设部分的驱动都在DeviceDrivers里做好了,具体的应用也就是如何利用驱动实现自己的功能。GPIO的使用还是比较简单的,用之前调用rt_hw_kr_init()初始化对应的IO,然后调用rt_pin_read()函数读取IO的状态即可。在我的应用中,由于不是简单的读取一个IO,并且要做一些软件滤波。故还有一层最终应用。代码如下: ``` void rt_hw_kr_init(void) { rt_pin_mode(RT_KEY1_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY2_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY3_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY4_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY5_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY6_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY7_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY8_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY9_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY10_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY11_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY12_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY13_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY14_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY15_PIN, PIN_MODE_INPUT); rt_pin_mode(RT_KEY16_PIN, PIN_MODE_INPUT); } rt_uint16_t read_kr(void) { union BitUnion16 temp; temp.Bit.Bit0 = rt_pin_read(RT_KEY1_PIN); temp.Bit.Bit1 = rt_pin_read(RT_KEY2_PIN); temp.Bit.Bit2 = rt_pin_read(RT_KEY3_PIN); temp.Bit.Bit3 = rt_pin_read(RT_KEY4_PIN); temp.Bit.Bit4 = rt_pin_read(RT_KEY5_PIN); temp.Bit.Bit5 = rt_pin_read(RT_KEY6_PIN); temp.Bit.Bit6 = rt_pin_read(RT_KEY7_PIN); temp.Bit.Bit7 = rt_pin_read(RT_KEY8_PIN); temp.Bit.Bit8 = rt_pin_read(RT_KEY9_PIN); temp.Bit.Bit9 = rt_pin_read(RT_KEY10_PIN); temp.Bit.Bit10 = rt_pin_read(RT_KEY11_PIN); temp.Bit.Bit11 = rt_pin_read(RT_KEY12_PIN); temp.Bit.Bit12 = rt_pin_read(RT_KEY13_PIN); temp.Bit.Bit13 = rt_pin_read(RT_KEY14_PIN); temp.Bit.Bit14 = rt_pin_read(RT_KEY15_PIN); temp.Bit.Bit15 = rt_pin_read(RT_KEY16_PIN); return temp.Word^0xFFFF; } /********************************************************/ #ifdef RT_USING_FINSH Uint8 lookforkrindex(Uint16 data) { Uint8 reval; switch (data) { case 0x0001:{reval = 1;}break; case 0x0002:{reval = 2;}break; case 0x0004:{reval = 3;}break; case 0x0008:{reval = 4;}break; case 0x0010:{reval = 5;}break; case 0x0020:{reval = 6;}break; case 0x0040:{reval = 7;}break; case 0x0080:{reval = 8;}break; case 0x0100:{reval = 9;}break; case 0x0200:{reval = 10;}break; case 0x0400:{reval = 11;}break; case 0x0800:{reval = 12;}break; case 0x1000:{reval = 13;}break; case 0x2000:{reval = 14;}break; case 0x4000:{reval = 15;}break; case 0x8000:{reval = 16;}break; default:{reval = 255;}break; } return reval; } #endif static void kr_thread_entry(void *parameter) { rt_uint8_t i; rt_uint16_t jumpflag,inputdata; static rt_uint16_t laststate,cntstartflag,cnt[16]; rt_hw_kr_init(); while (1) { inputdata = read_kr(); //读取硬件IO值 jumpflag = inputdata^laststate; laststate = inputdata; for(i = 0; i < 16;i++) { //判断是否有输入变化,有的话计数清零,重新计数 if(jumpflag & CompareCode* ) { cntstartflag ^= CompareCode*; cnt* = 0; } //计数,到达设定值后修改相应的位 if(cntstartflag & CompareCode*) { cnt* ++; if(cnt* > 1) { if(inputdata & CompareCode*) {//输入为1 #ifdef RT_USING_FINSH rt_kprintf("KR%d 1
",lookforkrindex(cntstartflag)); #endif } else {//输入为0 #ifdef RT_USING_FINSH rt_kprintf("KR%d 0
",lookforkrindex(cntstartflag)); #endif } //标志清零 cntstartflag &= ~CompareCode*; cnt* = 0; } } } rt_thread_delay(RT_TICK_PER_SECOND/50); } } int kr_init(void) { rt_err_t result; /* init led thread */ result = rt_thread_init(&kr_thread, "KR", kr_thread_entry, RT_NULL, (rt_uint8_t *)&kr_stack[0], sizeof(kr_stack), 22, 10); if (result == RT_EOK) { rt_thread_startup(&kr_thread); } return 0; } /* 导出到 msh 命令列表中 */ MSH_CMD_EXPORT(kr_init, read input pin);```最终的线程里即是我的最终应用,可以对输入信号进行软件滤波。 第三步 继电器输出 GPIO的输出和输入一样简单,不同的是输出控制调用的函数是rt_pin_write(); ``` //打开继电器控制函数 void relay_ctr(uint8_t argc, char *argv[]) { rt_uint8_t ch,on_off; ch = atoi((const char *)argv[1]); if(argc == 2) { switch(ch) { case 1:{ rt_pin_write(RT_RELAY1_PIN, rt_pin_read(RT_RELAY1_PIN)^1);}break; case 2:{ rt_pin_write(RT_RELAY2_PIN, rt_pin_read(RT_RELAY2_PIN)^1);}break; case 3:{ rt_pin_write(RT_RELAY3_PIN, rt_pin_read(RT_RELAY3_PIN)^1);}break; case 4:{ rt_pin_write(RT_RELAY4_PIN, rt_pin_read(RT_RELAY4_PIN)^1);}break; case 5:{ rt_pin_write(RT_RELAY5_PIN, rt_pin_read(RT_RELAY5_PIN)^1);}break; case 6:{ rt_pin_write(RT_RELAY6_PIN, rt_pin_read(RT_RELAY6_PIN)^1);}break; case 7:{ rt_pin_write(RT_RELAY7_PIN, rt_pin_read(RT_RELAY7_PIN)^1);}break; case 8:{ rt_pin_write(RT_RELAY8_PIN, rt_pin_read(RT_RELAY8_PIN)^1);}break; case 9:{ rt_pin_write(RT_RELAY9_PIN, rt_pin_read(RT_RELAY9_PIN)^1);}break; case 10:{ rt_pin_write(RT_RELAY10_PIN, rt_pin_read(RT_RELAY10_PIN)^1);}break; default: break; } } else if(argc == 3) { if(strcmp(argv[2], "on") == 0) { on_off = PIN_HIGH; } else if(strcmp(argv[2], "off") == 0) { on_off = PIN_LOW; } //控制 switch(ch) { case 1:{ rt_pin_write(RT_RELAY1_PIN, on_off);}break; case 2:{ rt_pin_write(RT_RELAY2_PIN, on_off);}break; case 3:{ rt_pin_write(RT_RELAY3_PIN, on_off);}break; case 4:{ rt_pin_write(RT_RELAY4_PIN, on_off);}break; case 5:{ rt_pin_write(RT_RELAY5_PIN, on_off);}break; case 6:{ rt_pin_write(RT_RELAY6_PIN, on_off);}break; case 7:{ rt_pin_write(RT_RELAY7_PIN, on_off);}break; case 8:{ rt_pin_write(RT_RELAY8_PIN, on_off);}break; case 9:{ rt_pin_write(RT_RELAY9_PIN, on_off);}break; case 10:{ rt_pin_write(RT_RELAY10_PIN, on_off);}break; default: break; } } } MSH_CMD_EXPORT(relay_ctr, relay control); void rt_hw_relay_init(void) { rt_pin_mode(RT_RELAY1_PIN, PIN_MODE_OUTPUT); rt_pin_mode(RT_RELAY2_PIN, PIN_MODE_OUTPUT); rt_pin_mode(RT_RELAY3_PIN, PIN_MODE_OUTPUT); rt_pin_mode(RT_RELAY4_PIN, PIN_MODE_OUTPUT); rt_pin_mode(RT_RELAY5_PIN, PIN_MODE_OUTPUT); rt_pin_mode(RT_RELAY6_PIN, PIN_MODE_OUTPUT); rt_pin_mode(RT_RELAY7_PIN, PIN_MODE_OUTPUT); rt_pin_mode(RT_RELAY8_PIN, PIN_MODE_OUTPUT); rt_pin_mode(RT_RELAY9_PIN, PIN_MODE_OUTPUT); rt_pin_mode(RT_RELAY10_PIN, PIN_MODE_OUTPUT); } static void relay_thread_entry(void *parameter) { unsigned int count = 0; rt_hw_relay_init(); while (1) { /* led1 on */ // rt_kprintf("relay on, count : %d
", count); // relay_ON(count); count++; if(count >= 10) { count = 0; rt_pin_write(RT_RELAY1_PIN, 0); rt_pin_write(RT_RELAY2_PIN, 0); rt_pin_write(RT_RELAY3_PIN, 0); rt_pin_write(RT_RELAY4_PIN, 0); rt_pin_write(RT_RELAY5_PIN, 0); rt_pin_write(RT_RELAY6_PIN, 0); rt_pin_write(RT_RELAY7_PIN, 0); rt_pin_write(RT_RELAY8_PIN, 0); rt_pin_write(RT_RELAY9_PIN, 0); rt_pin_write(RT_RELAY10_PIN, 0); rt_thread_delay(RT_TICK_PER_SECOND/2); } rt_thread_delay(RT_TICK_PER_SECOND); } } int relay_init(void) { rt_err_t result; /* init led thread */ result = rt_thread_init(&relay_thread, "relay", relay_thread_entry, RT_NULL, (rt_uint8_t *)&relay_stack[0], sizeof(relay_stack), 21, 10); if (result == RT_EOK) { rt_thread_startup(&relay_thread); } return 0; } /* 导出到 msh 命令列表中 */ MSH_CMD_EXPORT(relay_init, relay control); ```在输出控制部分,我做了一下shell命令,即可以通过输入命令实现继电器的控制,在后面会说到。 第四步 实现env配置GPIO所用管脚 要想实现env配置项目中的具体应用,实际上是在menuconfig里增加与自己项目相关的菜单项,这一点在新建标准工程的官方文档里有说明。 地址如下[https://www.rt-thread.org/docume ... p-standard-project/](https://www.rt-thread.org/document/site/rtthread-application-note/setup/standard-project/an0017-rtthread-setup-standard-project/) 由于LED闪烁功能用的是STD库的,没有使用menuconfig配置。只在输入输出中进行了修改。 添加menuconfig菜单需要修改的是Kconfig文件。格式如下: ![kconfig-hello.png](/uploads/201809/12/121345ysob9ddjws4esso4.png) 我修改之后的文件如下: ``` menu "Relay Pin Definition" config RT_RELAY1_PIN int "Relay1 Pin No" default 3 config RT_RELAY2_PIN int "Relay2 Pin No" default 4 config RT_RELAY3_PIN int "Relay3 Pin No" default 7 config RT_RELAY4_PIN int "Relay4 Pin No" default 8 config RT_RELAY5_PIN int "Relay5 Pin No" default 9 config RT_RELAY6_PIN int "Relay6 Pin No" default 1 config RT_RELAY7_PIN int "Relay7 Pin No" default 98 config RT_RELAY8_PIN int "Relay8 Pin No" default 97 config RT_RELAY9_PIN int "Relay9 Pin No" default 96 config RT_RELAY10_PIN int "Relay10 Pin No" default 95 endmenu menu "Key Pin Definition" config RT_KEY1_PIN int "key1 Pin No" default 51 config RT_KEY2_PIN int "key2 Pin No" default 52 config RT_KEY3_PIN int "key3 Pin No" default 54 config RT_KEY4_PIN int "key4 Pin No" default 56 config RT_KEY5_PIN int "key5 Pin No" default 58 config RT_KEY6_PIN int "key6 Pin No" default 60 config RT_KEY7_PIN int "key7 Pin No" default 62 config RT_KEY8_PIN int "key8 Pin No" default 67 config RT_KEY9_PIN int "key9 Pin No" default 70 config RT_KEY10_PIN int "key10 Pin No" default 71 config RT_KEY11_PIN int "key11 Pin No" default 77 config RT_KEY12_PIN int "key12 Pin No" default 80 config RT_KEY13_PIN int "key13 Pin No" default 81 config RT_KEY14_PIN int "key14 Pin No" default 82 config RT_KEY15_PIN int "key15 Pin No" default 83 config RT_KEY16_PIN int "key16 Pin No" default 84 endmenu ```修改完成后保存,在env里重新输入menuconfig命令即可。效果如下: ![TIM图片20180912133457.png](/uploads/201809/12/133616ui6s43cxxy4ysll3.png) ![TIM图片20180912133518.png](/uploads/201809/12/133621u4yru8f2wzk88ifw.png) 通过这样的配置。在rtconfig.h文件里会自动添加如下代码 ![TIM图片20180912133829.png](/uploads/201809/12/134037b888leqz8bvymdv2.png) 在自己的工程代码里面使用RT_RELAY1_PIN代替固定的管脚号。如果以后硬件有修改,直接在env里修改就可以了。 第五步 使用shell命令调试 使用shell命令调试主要是要导出shell命令。这个是内核的学习阶段就说过如何操作。在上面的代码中也有具体应用。运行效果如下 ![TIM图片20180912134722.png](/uploads/201809/12/134813deyf8j00h0bffbyh.png) 在输入带参数的命令的时候需要注意使用固定的格式,如我使用的的控制继电器函数,函数原型为void relay_ctr(uint8_t argc, char *argv[])。其中Uint8_argc表示的是输入的命令个数,即几个字符串。命令和参数都算一个字符串,命令和参数,还有参数和参数之间要用空格分开。char *argv[]是一个数组指针。这个数组里面存放的是输入字符串的指针。 ![TIM图片20180912135613.png](/uploads/201809/12/140320u6uwrun6rcswfsrj.png) 了解了这些,编程的时候就好处理了。这一点我在文档里没有找到明确的说明。据说在编程手册里有,我还有没有看。 在这次试验中,对GPIO频繁、大量的操作利用当前的文件结构感觉效率就有点儿低了,比如说在我的应用中,我每10ms就得读取16个IO的状态, 每读一个IO都需要执行比较复杂的操作,不知道有没有更好的解决办法。如果没有的话我打算在具体应用上使用STD库的擦操作方式。 ![TIM图片20180912135613.png](https://oss-club.rt-thread.org/uploads/201809/12/140336l5n1n17inwhbiiv0.png)
查看更多
0
个回答
默认排序
按发布时间排序
暂无答案,快来添加答案吧
撰写答案
登录
注册新账号
关注者
0
被浏览
1.8k
关于作者
吉帅虎
这家伙很懒,什么也没写!
提问
12
回答
12
被采纳
0
关注TA
发私信
相关问题
1
【内核学习】rtthread内核移植记录-STM32F103ZET6-HAL库
2
《内核学习营》+水一方+自用STM32F103VC 板RT-Thread内核移植分享
3
《内核学习营》+水一方+项目中创建标准的 RT-Thread工程
4
内核学习营+坦然+探索者stm32f407板子RT-thread循环点亮led灯
5
<内核学习营>+坦然+探索者stm32f407板子RT-thread串口字符点灯
6
<内核学习营>+坦然+探索者stm32f407板子RT-thread的pwm点灯实验
7
<内核学习营>+坦然+探索者stm32f407板子RT-thread串口实验
8
<内核学习营>+坦然+野火stm32f103板子RT-thread读写SD卡实验
9
<内核学习营>+坦然+探索者stm32f407板子RT-thread的RTC闹钟实验
10
【内核学习营】+王秀峰+led_rgb
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
【24嵌入式设计大赛】基于RT-Thread星火一号的智慧家居系统
2
RT-Thread EtherKit开源以太网硬件正式发布
3
如何在master上的BSP中添加配置yml文件
4
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
5
RT-Thread 发布 EtherKit开源以太网硬件!
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
MicroPython
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
15
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
5
次点赞
RTT_逍遥
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部