首页 > 代码库 > SmartOS之(C++)------输入输出端口类Port

SmartOS之(C++)------输入输出端口类Port

 

 

  SmartOS (C++)的GPIO驱动,兼容STM32F0/F1/F4/GD32F10x/GD32F1x0

 

  头文件

  

  1 #ifndef _Port_H_  2 #define _Port_H_  3   4 #include "Sys.h"  5 #include "ADC.h"  6   7 #ifdef STM32F4  8         #define GPIO_MAX_SPEED 100  9 #else 10         #define GPIO_MAX_SPEED 50 11 #endif 12  13 // 端口基类 14 // 用于管理一个端口,通过PinBit标识该组的哪些引脚。 15 // 子类初始化时先通过SetPort设置端口,备份引脚状态,然后Config通过gpio结构体配置端口,端口销毁时恢复引脚状态 16 class Port 17 { 18 public: 19     GPIO_TypeDef*        Group;                // 针脚组 20     Pin                                _Pin;                // 针脚 21     ushort                        PinBit;                // 组内引脚位。每个引脚一个位 22  23     Port& Set(Pin pin);                        // 设置引脚,并应用配置。 24         bool Empty() const { return _Pin == P0; } 25  26     virtual void Config();                // 确定配置,确认用对象内部的参数进行初始化 27  28     // 辅助函数 29     _force_inline static GPIO_TypeDef* IndexToGroup(byte index); 30     _force_inline static byte GroupToIndex(GPIO_TypeDef* group); 31  32 #if DEBUG 33         static bool Reserve(Pin pin, bool flag);        // 保护引脚,别的功能要使用时将会报错。返回是否保护成功 34         static bool IsBusy(Pin pin);        // 引脚是否被保护 35 #endif 36  37 protected: 38         Port(); 39         virtual ~Port(); 40  41     // 配置过程,由Config调用,最后GPIO_Init 42     virtual void OnConfig(GPIO_InitTypeDef& gpio); 43 #if DEBUG 44         virtual bool OnReserve(Pin pin, bool flag); 45 #endif 46  47 private: 48 #if defined(STM32F1) 49         ulong InitState;        // 备份引脚初始状态,在析构时还原 50 #endif 51 }; 52  53 // 输出口 54 class OutputPort : public Port 55 { 56 public: 57     bool OpenDrain;        // 是否开漏输出 58     bool Invert;        // 是否倒置输入输出 59     uint Speed;                // 速度 60  61     OutputPort() { Init(); } 62         // 普通输出一般采用开漏输出,需要倒置 63     OutputPort(Pin pin, bool invert = false, bool openDrain = false, uint speed = GPIO_MAX_SPEED) 64         { 65                 Init(invert, openDrain, speed); 66                 Set(pin); 67         } 68  69         // 整体写入所有包含的引脚 70     void Write(bool value); 71     void WriteGroup(ushort value);   // 整组写入 72         void Up(uint ms);        // 拉高一段时间后拉低 73         void Blink(uint times, uint ms);        // 闪烁多次 74  75     ushort ReadGroup();    // 整组读取 76         // 读取指定索引引脚。索引按照从小到大,0xFF表示任意脚为true则返回true 77     bool Read(byte index); 78     bool Read();                // Read() ReadReal() 的区别在  前者读输出  一个读输入    在开漏输出的时候有很大区别 79         bool ReadInput(); 80  81     static bool Read(Pin pin); 82     static void Write(Pin pin, bool value); 83  84     OutputPort& operator=(bool value) { Write(value); return *this; } 85     OutputPort& operator=(OutputPort& port) { Write(port.Read()); return *this; } 86     operator bool() { return Read(); } 87  88 protected: 89     virtual void OnConfig(GPIO_InitTypeDef& gpio); 90  91     void Init(bool invert = false, bool openDrain = false, uint speed = GPIO_MAX_SPEED) 92     { 93         OpenDrain = openDrain; 94         Speed = speed; 95         Invert = invert; 96     } 97  98 #if DEBUG 99         virtual bool OnReserve(Pin pin, bool flag);100 #endif101 };102 103 // 复用输出口104 class AlternatePort : public OutputPort105 {106 public:107         AlternatePort() : OutputPort() { Init(false, false); }108         // 复用输出一般采用推挽输出,不需要倒置109     AlternatePort(Pin pin, bool invert = false, bool openDrain = false, uint speed = GPIO_MAX_SPEED)110                 : OutputPort()111         {112                 Init(invert, openDrain, speed);113                 Set(pin);114         }115 116 protected:117     virtual void OnConfig(GPIO_InitTypeDef& gpio);118 119 #if DEBUG120         virtual bool OnReserve(Pin pin, bool flag);121 #endif122 };123 124 // 输入口125 class InputPort : public Port126 {127 public:128     typedef enum129     {130         PuPd_NOPULL = 0x00,131         PuPd_UP     = 0x01,132         PuPd_DOWN   = 0x02133     }PuPd_TypeDef;134 135     // 读取委托136     typedef void (*IOReadHandler)(Pin pin, bool down, void* param);137 138     uint ShakeTime;     // 抖动时间139     PuPd_TypeDef PuPd;  // 上拉下拉电阻140     bool Floating;      // 是否浮空输入141     bool Invert;                // 是否倒置输入输出142 143         InputPort() { Init(); }144     InputPort(Pin pin, bool floating = true, PuPd_TypeDef pupd = PuPd_UP)145         {146                 Init(floating, pupd);147                 Set(pin);148         }149 150     virtual ~InputPort();151 152     ushort ReadGroup();                        // 整组读取153     bool Read();                                // 读取状态154     static bool Read(Pin pin);        // 读取某个引脚155 156     void Register(IOReadHandler handler, void* param = NULL);   // 注册事件157 158     operator bool() { return Read(); }159 160 protected:161     // 函数命名为Init,而不作为构造函数,主要是因为用构造函数会导致再实例化一个对象,然后这个函数在那个新对象里面执行162     void Init(bool floating = true, PuPd_TypeDef pupd = PuPd_UP)163     {164                 PuPd = pupd;165         Floating = floating;166 167         _Registed = false;168         //ShakeTime = 20;169                 // 有些应用的输入口需要极高的灵敏度,这个时候不需要抖动检测170         ShakeTime = 0;171         Invert = false;172     }173 174     virtual void OnConfig(GPIO_InitTypeDef& gpio);175 176 #if DEBUG177         virtual bool OnReserve(Pin pin, bool flag);178 #endif179 180 private:181     bool _Registed;182 183     void RegisterInput(int groupIndex, int pinIndex, IOReadHandler handler, void* param);184     void UnRegisterInput(int pinIndex);185 };186 187 // 模拟输入输出口188 class AnalogInPort : public Port189 {190 public:191     AnalogInPort(Pin pin) { Set(pin); }192 193 protected:194     virtual void OnConfig(GPIO_InitTypeDef& gpio);195 };196 197 // 输出端口会话类。初始化时打开端口,超出作用域析构时关闭。反向操作可配置端口为倒置198 class PortScope199 {200 private:201         OutputPort* _port;202         bool _value;203 204 public:205         PortScope(OutputPort* port, bool value = http://www.mamicode.com/true)206         {207                 _port = port;208                 if(_port)209                 {210                         // 备份数值,析构的时候需要还原211                         _value = http://www.mamicode.com/port->Read();212                         *_port = value;213                 }214         }215 216         ~PortScope()217         {218                 if(_port) *_port = _value;219         }220 };221 222 #endif //_Port_H_223 源码实现224 225 #include "Port.h"226 227 #if defined(STM32F1) || defined(STM32F4)228 static const int PORT_IRQns[] = {229     EXTI0_IRQn, EXTI1_IRQn, EXTI2_IRQn, EXTI3_IRQn, EXTI4_IRQn, // 5个基础的230     EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn,    // EXTI9_5231     EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn   // EXTI15_10232 };233 #elif defined(STM32F0)234 static const int PORT_IRQns[] = {235     EXTI0_1_IRQn, EXTI0_1_IRQn, // 基础236     EXTI2_3_IRQn, EXTI2_3_IRQn, // 基础237     EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn,238     EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn   // EXTI15_10239 };240 #endif241 242 // 端口基本功能243 #define REGION_Port 1244 #ifdef REGION_Port245 Port::Port()246 {247         _Pin = P0;248         Group = NULL;249         PinBit = 0;250 }251 252 Port::~Port()253 {254 #if defined(STM32F1)255         // 恢复为初始化状态256         ushort bits = PinBit;257         int config = InitState & 0xFFFFFFFF;258         for(int i=0; i<16 && bits; i++, bits>>=1)259         {260                 if(i == 7) config = InitState >> 32;261                 if(bits & 1)262                 {263                         uint shift = (i & 7) << 2; // 每引脚4位264                         uint mask = 0xF << shift;  // 屏蔽掉其它位265 266                         GPIO_TypeDef* port = Group;267                         if (i & 0x08) { // bit 8 - 15268                                 port->CRH = port->CRH & ~mask | (config & mask);269                         } else { // bit 0-7270                                 port->CRL = port->CRL & ~mask | (config & mask);271                         }272                 }273         }274 #endif275 276 #if DEBUG277         // 解除保护引脚278         OnReserve(_Pin, false);279 #endif280 }281 282 // 单一引脚初始化283 Port& Port::Set(Pin pin)284 {285         //assert_param(pin != P0);286 287 #if DEBUG288         if(_Pin != P0) OnReserve(_Pin, false);289 #endif290 291     _Pin = pin;292         if(_Pin != P0)293         {294                 Group = IndexToGroup(pin >> 4);295                 PinBit = 1 << (pin & 0x0F);296         }297         else298         {299                 Group = NULL;300                 PinBit = 0;301         }302 303 #if defined(STM32F1)304         // 整组引脚的初始状态,析构时有选择恢复305         if(_Pin != P0) InitState = ((ulong)Group->CRH << 32) + Group->CRL;306 #endif307 308 #if DEBUG309         // 保护引脚310         if(_Pin != P0) OnReserve(_Pin, true);311 #endif312 313         if(_Pin != P0) Config();314 315         return *this;316 }317 318 void Port::Config()319 {320         GPIO_InitTypeDef gpio;321         // 特别要慎重,有些结构体成员可能因为没有初始化而酿成大错322         GPIO_StructInit(&gpio);323 324     OnConfig(gpio);325     GPIO_Init(Group, &gpio);326 }327 328 void Port::OnConfig(GPIO_InitTypeDef& gpio)329 {330     // 打开时钟331     int gi = _Pin >> 4;332 #ifdef STM32F0333     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOAEN << gi, ENABLE);334 #elif defined(STM32F1)335     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA << gi, ENABLE);336 #elif defined(STM32F4)337     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA << gi, ENABLE);338 #endif339 340     gpio.GPIO_Pin = PinBit;341 342 #ifdef STM32F1343         // PA15/PB3/PB4 需要关闭JTAG344         switch(_Pin)345         {346                 case PA15:347                 case PB3:348                 case PB4:349                 {350                         debug_printf("Close JTAG for P%c%d\r\n", _PIN_NAME(_Pin));351 352                         // PA15是jtag接口中的一员 想要使用 必须开启remap353                         RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);354                         GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);355                         break;356                 }357         }358 #endif359 }360 361 GPIO_TypeDef* Port::IndexToGroup(byte index) { return ((GPIO_TypeDef *) (GPIOA_BASE + (index << 10))); }362 byte Port::GroupToIndex(GPIO_TypeDef* group) { return (byte)(((int)group - GPIOA_BASE) >> 10); }363 #endif364 365 // 端口引脚保护366 #if DEBUG367 static ushort Reserved[8];                // 引脚保留位,记录每个引脚是否已经被保留,禁止别的模块使用368 369 // 保护引脚,别的功能要使用时将会报错。返回是否保护成功370 bool Port::Reserve(Pin pin, bool flag)371 {372     int port = pin >> 4, bit = 1 << (pin & 0x0F);373     if (flag) {374         if (Reserved[port] & bit) {375                         // 增加针脚已经被保护的提示,很多地方调用ReservePin而不写日志,得到False后直接抛异常376                         debug_printf("ReservePin P%c%d already reserved\r\n", _PIN_NAME(pin));377                         return false; // already reserved378                 }379         Reserved[port] |= bit;380 381                 debug_printf("ReservePin P%c%d\r\n", _PIN_NAME(pin));382     } else {383         Reserved[port] &= ~bit;384 385 #if defined(STM32F1)386                 int config = 0;387                 uint shift = (pin & 7) << 2; // 4 bits / pin388                 uint mask = 0xF << shift; // 屏蔽掉其它位389                 GPIO_TypeDef* port2 = IndexToGroup(port); // pointer to the actual port registers390                 if (pin & 0x08) { // bit 8 - 15391                         config = port2->CRH & mask;392                 } else { // bit 0-7393                         config = port2->CRL & mask;394                 }395 396                 config >>= shift;        // 移位到最右边397                 config &= 0xF;398                 debug_printf("UnReservePin P%c%d Config=0x%02x\r\n", _PIN_NAME(pin), config);399 #else400                 debug_printf("UnReservePin P%c%d\r\n", _PIN_NAME(pin));401 #endif402         }403 404     return true;405 }406 407 bool Port::OnReserve(Pin pin, bool flag)408 {409         return Reserve(pin, flag);410 }411 412 bool OutputPort::OnReserve(Pin pin, bool flag)413 {414         debug_printf("Output::");415 416         return Port::OnReserve(pin, flag);417 }418 419 bool AlternatePort::OnReserve(Pin pin, bool flag)420 {421         debug_printf("Alternate::");422 423         return Port::OnReserve(pin, flag);424 }425 426 bool InputPort::OnReserve(Pin pin, bool flag)427 {428         debug_printf("Input::");429 430         return Port::OnReserve(pin, flag);431 }432 433 // 引脚是否被保护434 bool Port::IsBusy(Pin pin)435 {436     int port = pin >> 4, sh = pin & 0x0F;437     return (Reserved[port] >> sh) & 1;438 }439 #endif440 441 // 引脚配置442 #define REGION_Config 1443 #ifdef REGION_Config444 void OutputPort::OnConfig(GPIO_InitTypeDef& gpio)445 {446 #ifndef STM32F4447         assert_param(Speed == 2 || Speed == 10 || Speed == 50);448 #else449         assert_param(Speed == 2 || Speed == 25 || Speed == 50 || Speed == 100);450 #endif451 452         Port::OnConfig(gpio);453 454         switch(Speed)455         {456                 case 2: gpio.GPIO_Speed = GPIO_Speed_2MHz; break;457 #ifndef STM32F4458                 case 10: gpio.GPIO_Speed = GPIO_Speed_10MHz; break;459 #else460                 case 25: gpio.GPIO_Speed = GPIO_Speed_25MHz; break;461                 case 100: gpio.GPIO_Speed = GPIO_Speed_100MHz; break;462 #endif463                 case 50: gpio.GPIO_Speed = GPIO_Speed_50MHz; break;464         }465 466 #ifdef STM32F1467         gpio.GPIO_Mode = OpenDrain ? GPIO_Mode_Out_OD : GPIO_Mode_Out_PP;468 #else469         gpio.GPIO_Mode = GPIO_Mode_OUT;470         gpio.GPIO_OType = OpenDrain ? GPIO_OType_OD : GPIO_OType_PP;471 #endif472 473         // 配置之前,需要根据倒置情况来设定初始状态,也就是在打开端口之前必须明确端口高低状态474         ushort dat = GPIO_ReadOutputData(Group);475         if(!Invert)476                 dat &= ~PinBit;477         else478                 dat |= PinBit;479         GPIO_Write(Group, dat);480 }481 482 void AlternatePort::OnConfig(GPIO_InitTypeDef& gpio)483 {484         OutputPort::OnConfig(gpio);485 486 #ifdef STM32F1487         gpio.GPIO_Mode = OpenDrain ? GPIO_Mode_AF_OD : GPIO_Mode_AF_PP;488 #else489         gpio.GPIO_Mode = GPIO_Mode_AF;490         gpio.GPIO_OType = OpenDrain ? GPIO_OType_OD : GPIO_OType_PP;491 #endif492 }493 494 void InputPort::OnConfig(GPIO_InitTypeDef& gpio)495 {496         Port::OnConfig(gpio);497 498 #ifdef STM32F1499         if(Floating)500                 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;501         else if(PuPd == PuPd_UP)502                 gpio.GPIO_Mode = GPIO_Mode_IPU;503         else if(PuPd == PuPd_DOWN)504                 gpio.GPIO_Mode = GPIO_Mode_IPD; // 这里很不确定,需要根据实际进行调整505 #else506         gpio.GPIO_Mode = GPIO_Mode_IN;507         //gpio.GPIO_OType = !Floating ? GPIO_OType_OD : GPIO_OType_PP;508 #endif509 }510 511 void AnalogInPort::OnConfig(GPIO_InitTypeDef& gpio)512 {513         Port::OnConfig(gpio);514 515 #ifdef STM32F1516         gpio.GPIO_Mode = GPIO_Mode_AIN; //517 #else518         gpio.GPIO_Mode = GPIO_Mode_AN;519         //gpio.GPIO_OType = !Floating ? GPIO_OType_OD : GPIO_OType_PP;520 #endif521 }522 #endif523 524 // 输出端口525 #define REGION_Output 1526 #ifdef REGION_Output527 ushort OutputPort::ReadGroup()    // 整组读取528 {529         return GPIO_ReadOutputData(Group);530 }531 532 bool OutputPort::Read()533 {534         // 转为bool时会转为0/1535         bool rs = GPIO_ReadOutputData(Group) & PinBit;536         return rs ^ Invert;537 }538 539 bool OutputPort::ReadInput()540 {541         bool rs = GPIO_ReadInputData(Group) & PinBit;542         return rs ^ Invert;543 }544 545 bool OutputPort::Read(Pin pin)546 {547         GPIO_TypeDef* group = _GROUP(pin);548         return (group->IDR >> (pin & 0xF)) & 1;549 }550 551 void OutputPort::Write(bool value)552 {553     if(value ^ Invert)554         GPIO_SetBits(Group, PinBit);555     else556         GPIO_ResetBits(Group, PinBit);557 }558 559 void OutputPort::WriteGroup(ushort value)560 {561     GPIO_Write(Group, value);562 }563 564 void OutputPort::Up(uint ms)565 {566     Write(true);567         Sys.Sleep(ms);568     Write(false);569 }570 571 void OutputPort::Blink(uint times, uint ms)572 {573         bool flag = true;574     for(int i=0; i<times; i++)575         {576                 Write(flag);577                 flag = !flag;578                 Sys.Sleep(ms);579         }580     Write(false);581 }582 583 // 设置端口状态584 void OutputPort::Write(Pin pin, bool value)585 {586     if(value)587         GPIO_SetBits(_GROUP(pin), _PORT(pin));588     else589         GPIO_ResetBits(_GROUP(pin), _PORT(pin));590 }591 #endif592 593 // 输入端口594 #define REGION_Input 1595 #ifdef REGION_Input596 /* 中断状态结构体 */597 /* 一共16条中断线,意味着同一条线每一组只能有一个引脚使用中断 */598 typedef struct TIntState599 {600     Pin Pin;601     InputPort::IOReadHandler Handler;        // 委托事件602         void* Param;        // 事件参数,一般用来作为事件挂载者的对象,然后借助静态方法调用成员方法603     bool OldValue;604 605     uint ShakeTime;     // 抖动时间606     int Used;   // 被使用次数。对于前5行中断来说,这个只会是1,对于后面的中断线来说,可能多个607 } IntState;608 609 // 16条中断线610 static IntState State[16];611 static bool hasInitState = false;612 613 void RegisterInput(int groupIndex, int pinIndex, InputPort::IOReadHandler handler);614 void UnRegisterInput(int pinIndex);615 616 InputPort::~InputPort()617 {618     // 取消所有中断619     if(_Registed) Register(NULL);620 }621 622 ushort InputPort::ReadGroup()    // 整组读取623 {624         return GPIO_ReadInputData(Group);625 }626 627 // 读取本组所有引脚,任意脚为true则返回true,主要为单一引脚服务628 bool InputPort::Read()629 {630         // 转为bool时会转为0/1631         bool rs = GPIO_ReadInputData(Group) & PinBit;632         return rs ^ Invert;633 }634 635 bool InputPort::Read(Pin pin)636 {637         GPIO_TypeDef* group = _GROUP(pin);638         return (group->IDR >> (pin & 0xF)) & 1;639 }640 641 // 注册回调  及中断使能642 void InputPort::Register(IOReadHandler handler, void* param)643 {644     if(!PinBit) return;645 646     // 检查并初始化中断线数组647     if(!hasInitState)648     {649         for(int i=0; i<16; i++)650         {651             IntState* state = &State[i];652             state->Pin = P0;653             state->Handler = NULL;654             state->Used = 0;655         }656         hasInitState = true;657     }658 659     byte gi = _Pin >> 4;660     ushort n = PinBit;661     for(int i=0; i<16 && n!=0; i++)662     {663         // 如果设置了这一位,则注册事件664         if(n & 0x01)665         {666             // 注册中断事件667             if(handler)668             {669                 IntState* state = &State[i];670                 state->ShakeTime = ShakeTime;671                 RegisterInput(gi, i, handler, param);672             }673             else674                 UnRegisterInput(i);675         }676         n >>= 1;677     }678 679     _Registed = handler != NULL;680 }681 682 #define IT 1683 #ifdef IT684 void GPIO_ISR (int num)  // 0 <= num <= 15685 {686         if(!hasInitState) return;687 688         IntState* state = State + num;689         if(!state) return;690 691         uint bit = 1 << num;692         bool value;693         //byte line = EXTI_Line0 << num;694         // 如果未指定委托,则不处理695         if(!state->Handler) return;696 697         // 默认20us抖动时间698         uint shakeTime = state->ShakeTime;699 700         do {701                 EXTI->PR = bit;   // 重置挂起位702                 value = http://www.mamicode.com/InputPort::Read(state->Pin); // 获取引脚状态703                 if(shakeTime > 0)704                 {705                         // 值必须有变动才触发706                         if(value =http://www.mamicode.com/= state->OldValue) return;707 708                         Time.Sleep(shakeTime); // 避免抖动709                 }710         } while (EXTI->PR & bit); // 如果再次挂起则重复711         //EXTI_ClearITPendingBit(line);712         // 值必须有变动才触发713         if(shakeTime > 0 && value =http://www.mamicode.com/= state->OldValue) return;714         state->OldValue =http://www.mamicode.com/ value;715         if(state->Handler)716         {717                 // 新值value为true,说明是上升,第二个参数是down,所以取非718                 state->Handler(state->Pin, !value, state->Param);719         }720 }721 722 void EXTI_IRQHandler(ushort num, void* param)723 {724 #if defined(STM32F1) || defined(STM32F4)725         // EXTI0 - EXTI4726         if(num <= EXTI4_IRQn)727                 GPIO_ISR(num - EXTI0_IRQn);728         else if(num == EXTI9_5_IRQn)729         {730                 // EXTI5 - EXTI9731                 uint pending = EXTI->PR & EXTI->IMR & 0x03E0; // pending bits 5..9732                 int num = 5; pending >>= 5;733                 do {734                         if (pending & 1) GPIO_ISR(num);735                         num++; pending >>= 1;736                 } while (pending);737         }738         else if(num == EXTI15_10_IRQn)739         {740                 // EXTI10 - EXTI15741                 uint pending = EXTI->PR & EXTI->IMR & 0xFC00; // pending bits 10..15742                 int num = 10; pending >>= 10;743                 do {744                         if (pending & 1) GPIO_ISR(num);745                         num++; pending >>= 1;746                 } while (pending);747         }748 #elif defined(STM32F0)749         switch(num)750         {751                 case EXTI0_1_IRQn:752                 {753                         uint pending = EXTI->PR & EXTI->IMR & 0x0003; // pending bits 0..1754                         int num = 0; pending >>= 0;755                         do {756                                 if (pending & 1) GPIO_ISR(num);757                                 num++; pending >>= 1;758                         } while (pending);759                         break;760                 }761                 case EXTI2_3_IRQn:762                 {763                         uint pending = EXTI->PR & EXTI->IMR & 0x000c; // pending bits 3..2764                         int num = 2; pending >>= 2;765                         do {766                                 if (pending & 1) GPIO_ISR(num);767                                 num++; pending >>= 1;768                         } while (pending);769                 }770                 case EXTI4_15_IRQn:771                 {772                         uint pending = EXTI->PR & EXTI->IMR & 0xFFF0; // pending bits 4..15773                         int num = 4; pending >>= 4;774                         do {775                                 if (pending & 1) GPIO_ISR(num);776                                 num++; pending >>= 1;777                         } while (pending);778                 }779         }780 #endif781 }782 #endif783 784 void SetEXIT(int pinIndex, bool enable)785 {786     /* 配置EXTI中断线 */787     EXTI_InitTypeDef ext;788     EXTI_StructInit(&ext);789     ext.EXTI_Line = EXTI_Line0 << pinIndex;790     ext.EXTI_Mode = EXTI_Mode_Interrupt;791     ext.EXTI_Trigger = EXTI_Trigger_Rising_Falling; // 上升沿下降沿触发792     ext.EXTI_LineCmd = enable ? ENABLE : DISABLE;793     EXTI_Init(&ext);794 }795 796 // 申请引脚中断托管797 void InputPort::RegisterInput(int groupIndex, int pinIndex, IOReadHandler handler, void* param)798 {799     IntState* state = &State[pinIndex];800     Pin pin = (Pin)((groupIndex << 4) + pinIndex);801     // 检查是否已经注册到别的引脚上802     if(state->Pin != pin && state->Pin != P0)803     {804 #if DEBUG805         debug_printf("EXTI%d can‘t register to P%c%d, it has register to P%c%d\r\n", groupIndex, _PIN_NAME(pin), _PIN_NAME(state->Pin));806 #endif807         return;808     }809     state->Pin = pin;810     state->Handler = handler;811         state->Param = param;812         state->OldValue = http://www.mamicode.com/Read(pin); // 预先保存当前状态值,后面跳变时触发中断813 814     // 打开时钟,选择端口作为端口EXTI时钟线815 #if defined(STM32F0) || defined(STM32F4)816     RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);817     SYSCFG_EXTILineConfig(groupIndex, pinIndex);818 #elif defined(STM32F1)819     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);820     GPIO_EXTILineConfig(groupIndex, pinIndex);821 #endif822 823         SetEXIT(pinIndex, true);824 825     // 打开并设置EXTI中断为低优先级826     Interrupt.SetPriority(PORT_IRQns[pinIndex], 1);827 828     state->Used++;829     if(state->Used == 1)830     {831         Interrupt.Activate(PORT_IRQns[pinIndex], EXTI_IRQHandler, this);832     }833 }834 835 void InputPort::UnRegisterInput(int pinIndex)836 {837     IntState* state = &State[pinIndex];838     // 取消注册839     state->Pin = P0;840     state->Handler = 0;841 842         SetEXIT(pinIndex, false);843 844     state->Used--;845     if(state->Used == 0)846     {847         Interrupt.Deactivate(PORT_IRQns[pinIndex]);848     }849 }850 #endif

 

End!
欢迎大家一起交流 ,分享程序员励志故事。   幸福的程序员 QQ群:技术分享 智能硬件群
技术分享
 

 

SmartOS之(C++)------输入输出端口类Port