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 #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群:  智能硬件群
时间: 2024-07-31 02:47:02

SmartOS之(C++)------输入输出端口类Port的相关文章

反射---输入一个类,打印出类中所有元素

package com.sadhu; import java.util.*; import java.lang.reflect.*; /** 反射---输入一个类,打印出类中所有元素 reflect包中有三个描述类元素的类:Field.Method.Constructor */ public class Sample {     public static void main(String[] args)     {         String name;//收集用户输入的类         

hadoop编程小技巧(5)---自定义输入文件格式类InputFormat

Hadoop代码测试环境:Hadoop2.4 应用:在对数据需要进行一定条件的过滤和简单处理的时候可以使用自定义输入文件格式类. Hadoop内置的输入文件格式类有: 1)FileInputFormat<K,V>这个是基本的父类,我们自定义就直接使用它作为父类: 2)TextInputFormat<LongWritable,Text>这个是默认的数据格式类,我们一般编程,如果没有特别指定的话,一般都使用的是这个:key代表当前行数据距离文件开始的距离,value代码当前行字符串:

Java的IO输入输出流类的介绍(有图)

一.字节流 1.InputStream/OutputStream(输入流与输出流几乎一一对应) 读取的方法   int read()   int read(byte[] buffer)   int read(byte[] buffer,int offset,int length) 2.各种类的区分,常用的9种(按处理的基本单位划分) 2.1.以字节数组为颗粒(颗粒就是基本单位的意思) ByteArrayInputStream 2.2.以文件为颗粒 FileInputStream 2.3.管道流(

输入输出流类iostream常用函数解析

原创作品,转载请注明出处:http://www.cnblogs.com/shrimp-can/p/5657192.html 一.成员类型 1. ios::fmtflags: 格式标志,常用来设置输出的格式,用于函数flags.setf.unsetf作为其参数或返回类型. field member constant effect when set independent flags boolalpha read/write bool elements as alphabetic strings (

java键盘输入 scanner类

平常工作中较少与键盘进行直接交互,但在一些测试方法中,需要有这样的功能. 一.可以用System.in.read()方法读取单个字符,但因为字符大小的限制,实际使用中有很多不方便的地方. 示例: char a = (char) System.in.read(); System.out.println(a); 需注意返回的是字符对应的ASCII码.要使用需要进行进一步处理. 二.可以将控制台输入的当做字符串处理,需要使用BufferedReader类以及InputStreamReader类. 示例

I学霸官方免费教程二十二:Java常用类之接收控制台输入 Scanner类

Scanner类(了解即可) 使用Scanner类接收键盘的输入1.创建Scanner对象的语法:Scanner scan = new Scanner(System.in);2.使用Scanner对象接收键盘输入:scan.next();//等待并接收键盘输入 实例: package common_class; import java.util.Scanner; /**  * 演示Scanner类  * 模拟用户登录  * @author 学霸联盟 - 赵灿  */ public class S

SmartOS之(C++)------硬件定时器类Timer

SmartOS (C++)的硬件定时器驱动,兼容STM32F0/F1/F4/GD32F10x/GD32F1x0 头文件 1 #ifndef __Timer_H__ 2 #define __Timer_H__ 3 4 #include "Sys.h" 5 6 // 定时器 7 class Timer 8 { 9 private: 10 TIM_TypeDef* _port; 11 byte _index; // 第几个定时器,从0开始 12 volatile bool _started;

实例_在文件中保留上次输入的类容

1 public class MainActivity extends Activity 2 { 3 private EditText et; 4 5 // 6 //创建活动时读取是否有上次保存的内容 7 // 8 @Override 9 protected void onCreate(Bundle savedInstanceState) 10 { 11 super.onCreate(savedInstanceState); 12 setContentView(R.layout.activity

7款优秀的开源数据挖掘工具

7款优秀的开源数据挖掘工具 IDMer说道:本文只对几种流行的开源数据挖掘平台进行了检视,比如Weka和R等.如果您想找寻更多的开源数据挖掘软件,可以到KDnuggets和Open Directory上查看.为了评测这些软件,我们用了UCI Machine Learning Repository上的心脏病诊断数据集. Tanagra Tanagra (http://eric.univ-lyon2.fr/wricco/tanagra/) 是使用图形界面的数据挖掘软件,采用了类似Windows资源管