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 #endif 101 }; 102 103 // 复用输出口 104 class AlternatePort : public OutputPort 105 { 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 DEBUG 120 virtual bool OnReserve(Pin pin, bool flag); 121 #endif 122 }; 123 124 // 输入口 125 class InputPort : public Port 126 { 127 public: 128 typedef enum 129 { 130 PuPd_NOPULL = 0x00, 131 PuPd_UP = 0x01, 132 PuPd_DOWN = 0x02 133 }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 DEBUG 177 virtual bool OnReserve(Pin pin, bool flag); 178 #endif 179 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 Port 189 { 190 public: 191 AnalogInPort(Pin pin) { Set(pin); } 192 193 protected: 194 virtual void OnConfig(GPIO_InitTypeDef& gpio); 195 }; 196 197 // 输出端口会话类。初始化时打开端口,超出作用域析构时关闭。反向操作可配置端口为倒置 198 class PortScope 199 { 200 private: 201 OutputPort* _port; 202 bool _value; 203 204 public: 205 PortScope(OutputPort* port, bool value = true) 206 { 207 _port = port; 208 if(_port) 209 { 210 // 备份数值,析构的时候需要还原 211 _value = 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_5 231 EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn // EXTI15_10 232 }; 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_10 239 }; 240 #endif 241 242 // 端口基本功能 243 #define REGION_Port 1 244 #ifdef REGION_Port 245 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 - 15 268 port->CRH = port->CRH & ~mask | (config & mask); 269 } else { // bit 0-7 270 port->CRL = port->CRL & ~mask | (config & mask); 271 } 272 } 273 } 274 #endif 275 276 #if DEBUG 277 // 解除保护引脚 278 OnReserve(_Pin, false); 279 #endif 280 } 281 282 // 单一引脚初始化 283 Port& Port::Set(Pin pin) 284 { 285 //assert_param(pin != P0); 286 287 #if DEBUG 288 if(_Pin != P0) OnReserve(_Pin, false); 289 #endif 290 291 _Pin = pin; 292 if(_Pin != P0) 293 { 294 Group = IndexToGroup(pin >> 4); 295 PinBit = 1 << (pin & 0x0F); 296 } 297 else 298 { 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 #endif 307 308 #if DEBUG 309 // 保护引脚 310 if(_Pin != P0) OnReserve(_Pin, true); 311 #endif 312 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 STM32F0 333 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 #endif 339 340 gpio.GPIO_Pin = PinBit; 341 342 #ifdef STM32F1 343 // PA15/PB3/PB4 需要关闭JTAG 344 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接口中的一员 想要使用 必须开启remap 353 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 354 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); 355 break; 356 } 357 } 358 #endif 359 } 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 #endif 364 365 // 端口引脚保护 366 #if DEBUG 367 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 reserved 378 } 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 / pin 388 uint mask = 0xF << shift; // 屏蔽掉其它位 389 GPIO_TypeDef* port2 = IndexToGroup(port); // pointer to the actual port registers 390 if (pin & 0x08) { // bit 8 - 15 391 config = port2->CRH & mask; 392 } else { // bit 0-7 393 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 #else 400 debug_printf("UnReservePin P%c%d\r\n", _PIN_NAME(pin)); 401 #endif 402 } 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 #endif 440 441 // 引脚配置 442 #define REGION_Config 1 443 #ifdef REGION_Config 444 void OutputPort::OnConfig(GPIO_InitTypeDef& gpio) 445 { 446 #ifndef STM32F4 447 assert_param(Speed == 2 || Speed == 10 || Speed == 50); 448 #else 449 assert_param(Speed == 2 || Speed == 25 || Speed == 50 || Speed == 100); 450 #endif 451 452 Port::OnConfig(gpio); 453 454 switch(Speed) 455 { 456 case 2: gpio.GPIO_Speed = GPIO_Speed_2MHz; break; 457 #ifndef STM32F4 458 case 10: gpio.GPIO_Speed = GPIO_Speed_10MHz; break; 459 #else 460 case 25: gpio.GPIO_Speed = GPIO_Speed_25MHz; break; 461 case 100: gpio.GPIO_Speed = GPIO_Speed_100MHz; break; 462 #endif 463 case 50: gpio.GPIO_Speed = GPIO_Speed_50MHz; break; 464 } 465 466 #ifdef STM32F1 467 gpio.GPIO_Mode = OpenDrain ? GPIO_Mode_Out_OD : GPIO_Mode_Out_PP; 468 #else 469 gpio.GPIO_Mode = GPIO_Mode_OUT; 470 gpio.GPIO_OType = OpenDrain ? GPIO_OType_OD : GPIO_OType_PP; 471 #endif 472 473 // 配置之前,需要根据倒置情况来设定初始状态,也就是在打开端口之前必须明确端口高低状态 474 ushort dat = GPIO_ReadOutputData(Group); 475 if(!Invert) 476 dat &= ~PinBit; 477 else 478 dat |= PinBit; 479 GPIO_Write(Group, dat); 480 } 481 482 void AlternatePort::OnConfig(GPIO_InitTypeDef& gpio) 483 { 484 OutputPort::OnConfig(gpio); 485 486 #ifdef STM32F1 487 gpio.GPIO_Mode = OpenDrain ? GPIO_Mode_AF_OD : GPIO_Mode_AF_PP; 488 #else 489 gpio.GPIO_Mode = GPIO_Mode_AF; 490 gpio.GPIO_OType = OpenDrain ? GPIO_OType_OD : GPIO_OType_PP; 491 #endif 492 } 493 494 void InputPort::OnConfig(GPIO_InitTypeDef& gpio) 495 { 496 Port::OnConfig(gpio); 497 498 #ifdef STM32F1 499 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 #else 506 gpio.GPIO_Mode = GPIO_Mode_IN; 507 //gpio.GPIO_OType = !Floating ? GPIO_OType_OD : GPIO_OType_PP; 508 #endif 509 } 510 511 void AnalogInPort::OnConfig(GPIO_InitTypeDef& gpio) 512 { 513 Port::OnConfig(gpio); 514 515 #ifdef STM32F1 516 gpio.GPIO_Mode = GPIO_Mode_AIN; // 517 #else 518 gpio.GPIO_Mode = GPIO_Mode_AN; 519 //gpio.GPIO_OType = !Floating ? GPIO_OType_OD : GPIO_OType_PP; 520 #endif 521 } 522 #endif 523 524 // 输出端口 525 #define REGION_Output 1 526 #ifdef REGION_Output 527 ushort OutputPort::ReadGroup() // 整组读取 528 { 529 return GPIO_ReadOutputData(Group); 530 } 531 532 bool OutputPort::Read() 533 { 534 // 转为bool时会转为0/1 535 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 else 556 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 else 589 GPIO_ResetBits(_GROUP(pin), _PORT(pin)); 590 } 591 #endif 592 593 // 输入端口 594 #define REGION_Input 1 595 #ifdef REGION_Input 596 /* 中断状态结构体 */ 597 /* 一共16条中断线,意味着同一条线每一组只能有一个引脚使用中断 */ 598 typedef struct TIntState 599 { 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/1 631 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 else 674 UnRegisterInput(i); 675 } 676 n >>= 1; 677 } 678 679 _Registed = handler != NULL; 680 } 681 682 #define IT 1 683 #ifdef IT 684 void GPIO_ISR (int num) // 0 <= num <= 15 685 { 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 = InputPort::Read(state->Pin); // 获取引脚状态 703 if(shakeTime > 0) 704 { 705 // 值必须有变动才触发 706 if(value == state->OldValue) return; 707 708 Time.Sleep(shakeTime); // 避免抖动 709 } 710 } while (EXTI->PR & bit); // 如果再次挂起则重复 711 //EXTI_ClearITPendingBit(line); 712 // 值必须有变动才触发 713 if(shakeTime > 0 && value == state->OldValue) return; 714 state->OldValue = 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 - EXTI4 726 if(num <= EXTI4_IRQn) 727 GPIO_ISR(num - EXTI0_IRQn); 728 else if(num == EXTI9_5_IRQn) 729 { 730 // EXTI5 - EXTI9 731 uint pending = EXTI->PR & EXTI->IMR & 0x03E0; // pending bits 5..9 732 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 - EXTI15 741 uint pending = EXTI->PR & EXTI->IMR & 0xFC00; // pending bits 10..15 742 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..1 754 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..2 764 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..15 773 int num = 4; pending >>= 4; 774 do { 775 if (pending & 1) GPIO_ISR(num); 776 num++; pending >>= 1; 777 } while (pending); 778 } 779 } 780 #endif 781 } 782 #endif 783 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 DEBUG 805 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 #endif 807 return; 808 } 809 state->Pin = pin; 810 state->Handler = handler; 811 state->Param = param; 812 state->OldValue = 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 #endif 822 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群: 智能硬件群