首页 > 代码库 > 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
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。