CC3200之GPIO引脚分析

2023-05-16

预备知识:
(1)volatile关键字:
volatile定义的变量一般为无需开发者自己赋值,会自动改变的变量。
在普通的程序中,编译器都具有优化功能,为了避免浪费计算机资源,会将重复或无用的语句删除。
大家观察下面一段代码。

//code1:
double gpio_input = 0printf("The GPIO Input1 is %f", gpio_input);

/*
光照传感器开始读取光照数据,并赋值给gpio_input
*/
printf("The GPIO Input2 is %f", gpio_input);

//code2:
volatile double gpio_input = 0printf("The GPIO Input1 is %f", gpio_input);

/*
光照传感器开始读取光照数据,并赋值给gpio_input
*/

printf("The GPIO Input2 is %f", gpio_input);

我们将一个GPIO INPUT的值赋值给gpio_input,第一段代码使用double类型来定义变量,并且两次输出的结果均为0;而第二次使用volatile类型来定义变量,它的两次结果分别为0和真实的光照数值

第一段代码:是因为编译器优化功能。编译器作为计算机的节耗小能手,不允许一个变量没有赋值而反复读取,因此它会自动过滤掉再次读取变量地址的数值的那段代码,直接从缓冲区中找到上次的值,而不是再一次根据变量地址访问主存器,进而找到主存中的变量值。而外设的数值改变一般都是存储器的数值变化,由于优化功能,光照传感器读取的数值无法被读取到,造成两次结果都是0。

[缓冲区的访问速率高于主存,但容量小于主存。因此,一般都是先从缓存中先查找变量,如果找不到,就一边从主存中查找,一边将查找的数据调至缓存,供下一次使用]

第二段代码:使用volatile关键字就可以告诉编译器gpio_input这个变量他自己会变,不要把它当成坏人,直接抹杀掉,因此下一次的读取是从主存中读取的值,即真实的外设读取的数值。

(2)HWREG(x)函数:
把x转为一个指向x的volatile unsigned long指针,然后从中取值
(3)当GPIO引脚输出1时,需要设置引脚值为0;反之,为1。
原因:引脚输出的电压都来自开发板的板供电压,点亮LED所需的电压最大为120mA,电流均来自芯片内部,如果很多LED灯,那么就等同于电压的叠加,此时通过芯片的电流很大,对芯片的伤害大,因此反过来,更有利于保护芯片。

切入主题

CC3200的GPIO引脚和其他arm核的处理器外设使用是一样的步骤。

step1:设置时钟

CC3200简单的函数调用对想要了解开发板的初学者来说是极大地便利了,但是作为想要进一步了解的“油头”青年,只能硬着头皮去分析功能的具体实现

  MAP_PRCMPeripheralClkEnable(PRCM_GPIOA1, PRCM_RUN_MODE_CLK);

这句话的含义是。开启GPIOA第二组时钟(下标从0开始)。
翻开这个函数的具体定义:

#define HWREG(x) (*((volatile unsigned long *)(x))) 
//外设寄存器地址放入内存,x为外设寄存器地址

void
PRCMPeripheralClkEnable(unsigned long ulPeripheral, unsigned long ulClkFlags)
{
  if(ulPeripheral != PRCM_ADC)
  {
    HWREG(ARCM_BASE + PRCM_PeriphRegsList[ulPeripheral].ulClkReg) |= ulClkFlags; 
     //启用指定的外设时钟,对PRCM_ADC不做任何操作,同时启动指定的外设寄存器
     //等同于 (*((volatile unsigned long *)(0x44025000 + PRCM_PeriphRegsList[ulPeripheral].ulClkReg)))
  }
  //如果是camera,为其重新定义时钟
  if(ulPeripheral == PRCM_CAMERA)
  {
    HWREG(ARCM_BASE + APPS_RCM_O_CAMERA_CLK_GEN) = 0x0404;
    //(*((volatile unsigned long *)(0x44025000 + 0x00000000)));
  }
}

step2:设置引脚

上一步我们对GPIOA第二组的时钟进行了设置,由于GPIO引脚具有两个方向,同时每组内包含8个引脚,因此,我们需要

设置组内引脚及方向

 MAP_PinTypeGPIO(PIN_64, PIN_MODE_0, false); 
 //引脚,引脚模式,开漏输出/推挽输出
 MAP_GPIODirModeSet(GPIOA1_BASE, 0x2, GPIO_DIR_MODE_OUT); 
 //基地址,组内号,方向

以上的code不难看出这是设置输出引脚PIN_64,由于引脚复用,因此当对同一引脚使用不同功能时,需要设置不同的引脚模式值,具体参考引脚模式对应表。
同样,我们看函数的定义部分

void PinTypeGPIO(unsigned long ulPin,unsigned long ulPinMode,tBoolean bOpenDrain)
{
    //设置标准开漏输出引脚
    if(bOpenDrain)
    {
            PinConfigSet(ulPin, PIN_STRENGTH_2MA, PIN_TYPE_OD);
    }
    else
    {
            PinConfigSet(ulPin, PIN_STRENGTH_2MA, PIN_TYPE_STD);
    }

    PinModeSet(ulPin, ulPinMode);
    //设置引脚模式
}

设置GPIO引脚类型设置

void PinConfigSet(unsigned long ulPin,unsigned long  ulPinStrength,unsigned long ulPinType)
{
  	unsigned long ulPad;
 	ulPad = g_ulPinToPadMap[ulPin & 0x3F];

    //将0x4402E144置1,允许输入。
    //但是这个寄存器0x4402E144是干什么的不太清楚
    HWREG(0x4402E144) &= ~((0x80 << ulPad) & (0x1E << 8));

    //计算寄存器地址,参考寄存器地址手册 	
    ulPad = ((ulPad << 2) + PAD_CONFIG_BASE);

    //找到寄存器地址,并向寄存器中写入设置值,参考每个引脚不同的配置值对应不同的功能
    HWREG(ulPad) = ((HWREG(ulPad) & ~(PAD_STRENGTH_MASK | PAD_TYPE_MASK)) |(ulPinStrength | ulPinType ));
  }
}

GPIO方向设置

void
GPIODirModeSet(unsigned long ulPort, unsigned char ucPins,
               unsigned long ulPinIO)
{
    ASSERT(GPIOBaseValid(ulPort)); //判断GPIO基地址是否合法
    ASSERT((ulPinIO == GPIO_DIR_MODE_IN) || (ulPinIO == GPIO_DIR_MODE_OUT));     //判断GPIO方向参数是否合法,输入为0,输出为1    
    HWREG(ulPort + GPIO_O_GPIO_DIR) = ((ulPinIO & 1) ?
                                  (HWREG(ulPort + GPIO_O_GPIO_DIR) | ucPins) :
                                  (HWREG(ulPort + GPIO_O_GPIO_DIR) & ~(ucPins)));
    //HWREG(ulPort + GPIO_O_GPIO_DIR)-》拿到GPIO组地址,ucPins拿到组内地址
}

至此,我们完成了配置。

step3:寄存器编程

CC3200官方自带的GPIO使用例程为流水灯

首先是函数GPIO_IF_LedConfigure,此函数中的GPIO_IF_GetPortNPin函数为主要的设置函数,此函数是
根据给定的GPIO值计算出引脚的GPIO基地址值和组内引脚值

GPIO_IF_LedConfigure(LED1|LED2|LED3);//同时配置3个GPIO引脚

void GPIO_IF_GetPortNPin(unsigned char ucPin, unsigned int *puiGPIOPort, unsigned char *pucGPIOPin)
{
    *pucGPIOPin = 1 << (ucPin % 8);    //组内序号从0开始,按此计算得到组内位权
    *puiGPIOPort = (ucPin / 8);       //每组有8个引脚,计算得出所属的GPIO组
    *puiGPIOPort = ulReg[*puiGPIOPort];    //取GPIO基地址值
}

拿到了引脚的GPIO基地址值和组内引脚值,接下来我们就需要针对具体GPIO引脚进行0/1的设置了,针对
流水灯中的一个灯的具体设置进行分析
其他设置是相同的步骤

    while(1)
    {
        MAP_UtilsDelay(8000000);
        GPIO_IF_LedOn(MCU_RED_LED_GPIO); //gpio9引脚置1,点亮LED
        MAP_UtilsDelay(8000000);
        GPIO_IF_LedOff(MCU_RED_LED_GPIO);//gpio9引脚置0,关闭LED
    }

进入GPIO_IF_LedOn函数体内部,其主要作用的是MAP_GPIOPinWrite函数,其主要功能为
设置GPIO引脚值,点灯

GPIO_IF_Set(GPIO_LED1, g_uiLED1Port, g_ucLED1Pin, 1);

void GPIO_IF_Set(unsigned char ucPin, unsigned char ucGPIOValue)
{
	...........
    ucGPIOValue = ucGPIOValue << (ucPin % 8);//gpio值为1时,ucGPIOValue 值为0;反之,值为1
    ...........
}


void GPIOPinWrite(unsigned long ulPort, unsigned char ucPins, unsigned char ucVal)
{
    ASSERT(GPIOBaseValid(ulPort));
    HWREG(ulPort + (GPIO_O_GPIO_DATA + (ucPins << 2))) = ucVal;  //ucVal表示要配置gpio组内的第几个引脚的位值0/1,将对应的位值写入ucPins指定的输出引脚
}

GPIO_IF_LedOff函数也是相同的配置

延时函数UtilsDelay


    __asm(     //_asm表示内联汇编,即在C/C++里使用汇编指令
    	  "    .sect \".text:UtilsDelay\"\n"
          "    .clink\n"
          "    .thumbfunc UtilsDelay\n"
          "    .thumb\n"
          "    .global UtilsDelay\n"
          "UtilsDelay:\n"
          "    subs r0, #1\n"   //r0-1;注意sub r0,r0,#1<——>r0=r0-1放到r0 
          "    bne.n UtilsDelay\n"    //16位的BNE指令,“不相等(或不为0)跳转指令”,如果r0不为0就跳转到后面指定的地址,继续执行;为0,则继续执行下面语句
          "    bx lr\n");    //转到lr中存放的地址处

lr:连接寄存器(Link Register, LR),在ARM体系结构中LR的特殊用途有两种:一、保存子程序返回地址;二、当异常发生时,LR中保存的值等于异常发生时PC的值减4(或者减2),因此在各种异常模式下可以根据LR的值返回到异常发生前的相应位置继续执行。
这段汇编还有点不太懂

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CC3200之GPIO引脚分析 的相关文章

随机推荐

  • ROS “is neither a launch file in package”报错

    一般是没找着你的package配置文件 xff0c 运行 rospack find package 名 查看能否找到包 xff0c 找不到的话把你的包拷贝到workspace路径下 xff0c cd到你的workspace路径 然后运行 c
  • bvh-converter将bvh文件输出为csv文件失败,原因竟是numpy版本不匹配

    最近做的东西需要将bvh数据处理成xyz坐标 xff0c 在下面这篇文章找到了方法 xff1a 57条消息 人体动作捕捉格式BVH及其与三维坐标的转换 三维视频转bvh 零度蛋花粥的博客 CSDN博客 通过pip导入bvh converte
  • C++实验:多态性与虚函数

    C 43 43 实验 xff1a 多态性与虚函数 1 实验目的 xff08 1 xff09 了解多态性的概念 xff08 2 xff09 了解虚函数的作用及使用方法 xff08 3 xff09 了解静态关联和动态关联的概念和用法 xff08
  • 2014流水账

    欢迎转载 xff0c 转载请注明出处 本文地址 xff1a http blog csdn net zhenggaoxing article details 42386821 三天元旦小长假结束了 xff0c 先来回顾下三天的假期 xff1a
  • IOS中文排序学习

    前言 xff1a 最近有中文排序的需要 xff0c 发现系统没有提供中文排序的方法 xff0c 于是参考学习了网上前辈的代码实现了中文排序功能 xff0c 本文记录的就是学习实现中文排序的过程 实现英文排序 系统提供了英文排序的方法 写了一
  • IOS 定制中间突出UItabBar

    前言 xff1a 公司的项目需要定制一个中间突出的TabBar xff0c 在github 上找到一份可以参考的代码 xff08 虽然是四年前的 xff0c 但是还是很有参考价值 xff09 网址 xff1a https github co
  • Xcode删除所有断点

    问题是这样的 xff1a 接手新的项目 xff0c 顿时吓尿了 xff1a 整个程序有无数个断点 xff0c 那么如何一次性删除呢 xff1f 如下图 xff1a 点击Belete Breakpoints 就可以了
  • VSCode重新启用“错误波形提示”

    2020 06 09 更新常见问题 昨天晚上写伪码的时候 xff0c 看着VSCode的错误提示实在是心烦 xff0c 就手贱点了一下 禁用错误波形提示 xff0c 也就是disable error squiggles xff0c 但写完之
  • TortoiseSVN使用教程[多图超详细]

    安装及下载client 端 下载Windows 端程序 xff1a http tortoisesvn net downloads 一般而言 xff0c 如果是32 bit的Windows XP 应该使用TortoiseSVN 1 4 x x
  • 将UIColor转换为RGB值

    objc view plain copy 将UIColor转换为RGB值 NSMutableArray changeUIColorToRGB UIColor color NSMutableArray RGBStrValueArr 61 NS
  • 业余时间你在做什么,你就会变成什么样的人?

    改变 xff0c 从业余时间开始 博客定位 xff1a 技术 43 思考 其余统统不要 2017 xff0c 我来了 xff01
  • Xcode9 无证书真机调试

    写在前面 公司分配了新的测试机 证书99台名额已满 所以上网找教程 学习了一下如何使用Xcode无证书进行真机调试 一 创建证书 1 运行Xcode xff0c Xcode Preference 添加账号 xff08 能在appstore下
  • CSP考试复习:第一单元 C++语言基础 1.1 程序结构

    第一单元 C 43 43 语言基础 1 1 程序结构 1 程序框架 注释 xff1a 注释有两种 xff0c 一种是 xff0c 另一种是 必须单独放置一行 xff0c 或代码所在行 的后面 xff1b 而 成对存在 xff0c 可以插入到
  • Intel Realsense T265开箱测试

    前言 xff1a 最近因为要做VIO xff0c 在实验室蹭到一个Realsense T265来用 xff0c 仅此记录下简单测试过程 xff08 官方文档写非常清楚 xff0c 建议详细阅读 xff0c 链接 xff1a https gi
  • posix thread介绍

    xfeff xfeff posix thread是 操作系统级 xff08 OS level xff09 的API规范 xff0c 主要用来定义线程及线程间同步的相关操作 xff0c 采用C语言定义 posix规范主要在unix like类
  • PX4飞控之自主起飞Takeoff控制逻辑

    本文主要以PX4飞控1 5 5版本为例 xff0c 介绍Navigator中自主起飞 xff08 Takeoff xff09 算法控制逻辑 注 xff1a mission任务中的自主起飞与此模块不同 Takeoff与导航中的其他模块类似 x
  • PX4飞控之导航及任务架构

    本文重点介绍PX4飞控的Navigator和mission控制框架和逻辑 Navigator导航部分是无人机自主飞行控制的核心所在 xff0c 其中包括自主起飞 自主降落 自主返航 自主任务以及GPS失效保护等各个部分 搞懂这个部分有助于理
  • PX4飞控之位置控制(1)整体架构

    位置控制是无人机飞控的核心算法之一 xff0c 一方面根据commander中的flag标志位和Navigator中提供的航点信息进行控制 xff08 自主模式下 xff09 xff0c 另一方面得到期望姿态角 xff08 setpoint
  • spring整合ehcache找不到org.springframework.cache.ehcache.EhCacheCacheManager的解决方案

    一般org springframework cache ehcache EhCacheCacheManager和org springframework cache ehcache EhCacheManagerFactoryBean会同时找不
  • CC3200之GPIO引脚分析

    预备知识 xff1a xff08 1 xff09 volatile关键字 xff1a volatile定义的变量一般为无需开发者自己赋值 xff0c 会自动改变的变量 在普通的程序中 xff0c 编译器都具有优化功能 xff0c 为了避免浪