mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-05-04 20:17:45 +00:00
98_Arducounter.pm: added firmware for arduino
git-svn-id: https://svn.fhem.de/fhem/trunk@13346 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
c20f22f686
commit
0b776b2086
501
fhem/FHEM/firmware/ArduCounter.hex
Executable file
501
fhem/FHEM/firmware/ArduCounter.hex
Executable file
@ -0,0 +1,501 @@
|
||||
:100000000C9456010C947E010C947E010C947008A3
|
||||
:100010000C944B080C9426080C947E010C947E01E1
|
||||
:100020000C947E010C947E010C947E010C947E0154
|
||||
:100030000C947E010C947E010C947E010C947E0144
|
||||
:100040000C94DC070C947E010C94AA070C94840792
|
||||
:100050000C947E010C947E010C947E010C947E0124
|
||||
:100060000C947E010C947E014572726F723A2000EE
|
||||
:1000700041726475436F756E7465722056312E3807
|
||||
:1000800000000000002300260029002C2061766774
|
||||
:10009000206C656E20002C206C61737420617420CC
|
||||
:1000A000004D202020666972737420617420002046
|
||||
:1000B00052656A2000206D73002920696E2000209F
|
||||
:1000C000282B002C20636F756E7420002C206E6F1F
|
||||
:1000D000206D696E206C656E002066616C6C696EC7
|
||||
:1000E000670020726973696E6700206D73002C20B1
|
||||
:1000F0006D696E206C656E20006368616E676500D7
|
||||
:1001000066616C6C696E6700726973696E67002C5A
|
||||
:1001100020694D6F646520005043496E74207069FA
|
||||
:100120006E20005374617274656400000000080062
|
||||
:1001300002010000030407000000000000000000AE
|
||||
:10014000000000250028002B0000000000240027EC
|
||||
:10015000002A0020004D20646566696E6564207089
|
||||
:10016000696E2000416464496E7400496C6C656777
|
||||
:10017000616C2070696E2073706563696669636184
|
||||
:1001800074696F6E2000496C6C6567616C207069E2
|
||||
:100190006E2073706563696669636174696F6E2050
|
||||
:1001A0000004040404040404040202020202020320
|
||||
:1001B000030303030301020408102040800102042A
|
||||
:1001C0000810200102040810204D2072656D6F7622
|
||||
:1001D0006564200052656D496E7400496C6C6567FA
|
||||
:1001E000616C2070696E2073706563696669636114
|
||||
:1001F00074696F6E20002000200020004D20696E81
|
||||
:1002000074657276616C732073657420746F20005E
|
||||
:1002100073697A6500204D696C6C697365636F6EF4
|
||||
:100220006473004D204E657874207265706F72742F
|
||||
:1002300020696E200020004D2070696E20004D2046
|
||||
:100240006D696E20636F756E7420004D206D696E50
|
||||
:1002500020696E74657276616C20004D206D617846
|
||||
:1002600020696E74657276616C20004D206E6F722D
|
||||
:100270006D616C20696E74657276616C20004D2032
|
||||
:100280005374617475733A200048656C6C6F00207C
|
||||
:100290004100204C00204600205800204E002054F1
|
||||
:1002A000002044002043005200000F0F11241FBE05
|
||||
:1002B000CFEFD8E0DEBFCDBF11E0A0E0B1E0E4EFCA
|
||||
:1002C000FEE102C005900D92A034B107D9F726E0F7
|
||||
:1002D000A0E4B1E001C01D92A836B207E1F711E039
|
||||
:1002E000C6E5D1E004C02197FE010E946D0FC5351F
|
||||
:1002F000D107C9F70E9495080C94780F0C94000060
|
||||
:10030000E091CB05F091CC050190F081E02D682FB4
|
||||
:100310008BEC95E009940F931F93CF93DF938C019F
|
||||
:10032000C0E0D0E0F801EC0FFD1F6491662371F08E
|
||||
:10033000E091CB05F091CC050190F081E02D8BECA4
|
||||
:1003400095E00995892B11F02196ECCFCE01DF9134
|
||||
:10035000CF911F910F910895CF92DF92EF92FF926C
|
||||
:100360000F931F93CF93DF936C017A018B01C0E051
|
||||
:10037000D0E0CE15DF0589F0D8016D918D01D60151
|
||||
:10038000ED91FC910190F081E02DC6010995892B3A
|
||||
:1003900011F47E0102C02196ECCFC701DF91CF910D
|
||||
:1003A0001F910F91FF90EF90DF90CF900895FC0187
|
||||
:1003B000918D828D981761F0828DDF01A80FB11D9C
|
||||
:1003C0005D968C91928D9F5F9F73928F90E00895C0
|
||||
:1003D0008FEF9FEF0895FC01918D828D981731F07A
|
||||
:1003E000828DE80FF11D858D90E008958FEF9FEFCE
|
||||
:1003F0000895FC01918D228D892F90E0805C9F4FA4
|
||||
:10040000821B91098F73992708958BEC95E00E94C8
|
||||
:10041000F90121E0892B09F420E0822F0895FC01E5
|
||||
:10042000848DDF01A80FB11DA35ABF4F2C91848D7D
|
||||
:1004300090E001968F739927848FA689B7892C93B2
|
||||
:10044000A089B1898C9180648C93938D848D98134D
|
||||
:1004500006C00288F389E02D80818F7D8083089516
|
||||
:10046000EF92FF920F931F93CF93DF93EC0181E004
|
||||
:10047000888F9B8D8C8D981305C0E889F9898081C0
|
||||
:1004800085FD24C0F62E0B8D10E00F5F1F4F0F73FC
|
||||
:100490001127E02E8C8DE8120CC00FB607FCFACFA6
|
||||
:1004A000E889F989808185FFF5CFCE010E940F028E
|
||||
:1004B000F1CF8B8DFE01E80FF11DE35AFF4FF08263
|
||||
:1004C0000B8FEA89FB898081806207C0EE89FF89F2
|
||||
:1004D0006083E889F98980818064808381E090E08D
|
||||
:1004E000DF91CF911F910F91FF90EF900895CF93DF
|
||||
:1004F000DF93EC01888D8823C9F0EA89FB8980812C
|
||||
:1005000085FD05C0A889B9898C9186FD0FC00FB6FD
|
||||
:1005100007FCF5CF808185FFF2CFA889B9898C913E
|
||||
:1005200085FFEDCFCE010E940F02E7CFDF91CF9183
|
||||
:10053000089580E090E0892B29F00E940502811146
|
||||
:100540000C94000008953FB7F894809108029091B0
|
||||
:100550000902A0910A02B0910B0226B5A89B05C022
|
||||
:100560002F3F19F00196A11DB11D3FBFBA2FA92F32
|
||||
:10057000982F8827820F911DA11DB11DBC01CD01AF
|
||||
:1005800042E0660F771F881F991F4A95D1F708959B
|
||||
:100590002FB7F894609104027091050280910602D1
|
||||
:1005A000909107022FBF08952F923F924F925F9232
|
||||
:1005B0006F927F928F929F92AF92BF92CF92DF9273
|
||||
:1005C000EF92FF920F931F93CF93DF93CDB7DEB7D8
|
||||
:1005D00060970FB6F894DEBF0FBECDBF082F0E9404
|
||||
:1005E000C8026B017C01202F30E0F901EE0FFF1FE4
|
||||
:1005F000EB57FF4FA591B4916C91F901E05CFE4F70
|
||||
:10060000708176276083220F331FF901E25EFE4F6F
|
||||
:100610000190F081E02D8081782309F4F8C0000F6B
|
||||
:10062000000F000F40E050E011E0A1E0B0E0042E28
|
||||
:1006300001C0AA0F0A94EAF7872F8A2309F4E1C0C0
|
||||
:10064000202F240F30E0F901E45FFD4F80818130DD
|
||||
:1006500069F0833021F4862F8A2341F4D2C082309E
|
||||
:1006600009F0CFC0862F8A2309F0CBC01901220CD4
|
||||
:10067000331CF101E156FC4F408051805A8249827F
|
||||
:10068000C901880F991F880F991F452809F47EC05A
|
||||
:10069000A623F901E45CFD4FAA2321F0A081A33039
|
||||
:1006A00061F403C0A081A23041F4FC01ED55FE4F7E
|
||||
:1006B000C082D182E282F382A4C0FC01ED55FE4FDC
|
||||
:1006C000408051806280738049865A866B867C8622
|
||||
:1006D000DC01AD5BBE4F4D905D906D907C901397AB
|
||||
:1006E0004D825E826F827886408051806280738006
|
||||
:1006F0004601570184189508A608B7088D869E867E
|
||||
:10070000AF86B88ACD92DD92ED92FC921397698004
|
||||
:100710007A802301612C712C49825A826B827C82FF
|
||||
:1007200084149504A604B704A8F089849A84AB8441
|
||||
:10073000BC844D805E806F80788484189508A608FC
|
||||
:10074000B70849805A806B807C8084149504A60485
|
||||
:10075000B70448F4F101E159FC4F80819181019681
|
||||
:10076000918380834EC0FC01E158FD4F80809180D1
|
||||
:10077000A280B3804D845E846F847888480C591CB5
|
||||
:100780006A1C7B1C4082518262827382FC01E157A9
|
||||
:10079000FB4FC082D182E282F382FC01E152FD4F25
|
||||
:1007A00080809180A280B38089288A288B2821F4B8
|
||||
:1007B000C082D182E282F382F901EC5AFD4F20819E
|
||||
:1007C000222379F0FC01E15DFB4F80819181A281C0
|
||||
:1007D000B3810196A11DB11D80839183A283B38350
|
||||
:1007E00010C0DC01A157BB4F8D909D90AD90BC9087
|
||||
:1007F000DC01A151BB4F8D929D92AD92BC9213979B
|
||||
:1008000010834F5F5F4F4830510509F00ECF60965F
|
||||
:100810000FB6F894DEBF0FBECDBFDF91CF911F9111
|
||||
:100820000F91FF90EF90DF90CF90BF90AF909F908F
|
||||
:100830008F907F906F905F904F903F902F90089592
|
||||
:10084000CF93DF93C0E7D0E0F0E0C038DF0731F0AE
|
||||
:10085000FE0184910E9480012196F6CFDF91CF9115
|
||||
:100860000895CF93DF93C8E6D0E0F0E0CF36DF07FE
|
||||
:1008700031F0FE0184910E9480012196F6CFDF9134
|
||||
:10088000CF910895E82FF0E0EF55FE4FE491E2504C
|
||||
:10089000E13011F4865005C0877098E0E99F800D23
|
||||
:1008A000112490E0089542E050E06CE371E08BEC9D
|
||||
:1008B00095E00C94AC01CF93DF930E948B01EC0187
|
||||
:1008C0000E9453048C0F9D1FDF91CF9108958F924A
|
||||
:1008D0009F92AF92BF92CF92DF92EF92FF920F93CF
|
||||
:1008E0001F93CF93DF930E94C8020FEA15E0AFEC8D
|
||||
:1008F000CA2EA3E0DA2ECFE9D3E0AFE3B3E02FE4D2
|
||||
:10090000822E25E0922E20E030E0BB24BA94F8013C
|
||||
:10091000B1928F01A9014C5A5D4FFA011082A901D1
|
||||
:10092000440F551F440F551FFA01E15DFB4F108224
|
||||
:10093000118212821382F601119211921192119278
|
||||
:100940006F01FA01E151FB4F6083718382839383CE
|
||||
:10095000FA01E157FB4F6083718382839383FA012D
|
||||
:10096000ED55FE4F60837183828393834D5B5E4FB1
|
||||
:10097000FA01608371838283938319921992A9018A
|
||||
:10098000440F551F41595C4FFA01118210821D928C
|
||||
:100990001D92F40161937193819391934F012F5FA5
|
||||
:1009A0003F4F2831310509F0B2CF0E94C8020091B3
|
||||
:1009B0000601109107012091080130910901DC0125
|
||||
:1009C000CB01800F911FA21FB31F8093C705909387
|
||||
:1009D000C805A093C905B093CA05E091DB05F09165
|
||||
:1009E000DC0582E08083E091D705F091D805108284
|
||||
:1009F000E091D905F091DA0583E380831092E30555
|
||||
:100A0000E091DF05F091E00586E08083E091DD056F
|
||||
:100A1000F091DE05808180618083E091DD05F091B9
|
||||
:100A2000DE05808188608083E091DD05F091DE0540
|
||||
:100A3000808180688083E091DD05F091DE05808112
|
||||
:100A40008F7D80830E94A3024B015C0184EFC82E3E
|
||||
:100A5000DD24D394E12CF12C0E94A302DC01CB0114
|
||||
:100A600088199909AA09BB09883E9340A105B105D7
|
||||
:100A700058F0F1E0CF1AD108E108F10828EE820E13
|
||||
:100A800023E0921EA11CB11CC114D104E104F104A5
|
||||
:100A900019F778940E9453040E94200483E291E0A5
|
||||
:100AA000DF91CF911F910F91FF90EF90DF90CF904A
|
||||
:100AB000BF90AF909F908F900C945B048F929F9209
|
||||
:100AC000AF92BF920F931F93CF93DF93CDB7DEB753
|
||||
:100AD000A1970FB6F894DEBF0FBECDBF19A242306A
|
||||
:100AE00008F44AE08E010F5D1F4F842E912CA12C3B
|
||||
:100AF000B12CA50194010E943C0FE62FB901CA0157
|
||||
:100B000001501109EA3014F4E05D01C0E95CD8013C
|
||||
:100B1000EC93232B242B252B61F70115110571F084
|
||||
:100B2000F80101900020E9F73197AF01401B510B0C
|
||||
:100B3000B8018BEC95E00E94AC0102C080E090E02F
|
||||
:100B4000A1960FB6F894DEBF0FBECDBFDF91CF9157
|
||||
:100B50001F910F91BF90AF909F908F9008954AE0A2
|
||||
:100B60000C945E05CF93DF93BC0180E090E04AE0F7
|
||||
:100B70000E945E05EC010E9453048C0F9D1FDF91C3
|
||||
:100B8000CF910895CF92DF92EF92FF92CF93DF93B0
|
||||
:100B900097FF19C06B017C018DE20E948001EC017E
|
||||
:100BA00066277727CB016C197D098E099F094AE0DA
|
||||
:100BB0000E945E058C0F9D1FDF91CF91FF90EF90FB
|
||||
:100BC000DF90CF9008954AE0DF91CF91FF90EF90B2
|
||||
:100BD000DF90CF900C945E05CF93DF93BC01990F0B
|
||||
:100BE000880B990B0E94C205EC010E9453048C0FE4
|
||||
:100BF0009D1FDF91CF910895CF93DF934AE00E942C
|
||||
:100C00005E05EC010E9453048C0F9D1FDF91CF9174
|
||||
:100C100008952F923F924F925F926F927F928F92A0
|
||||
:100C20009F92AF92BF92CF92DF92EF92FF920F937B
|
||||
:100C30001F93CF93DF93CDB7DEB727970FB6F89406
|
||||
:100C4000DEBF0FBECDBF8983282E312CC101880F96
|
||||
:100C5000991F880F991F9F838E83FC01E157FB4FDB
|
||||
:100C6000C080D180E280F3808C0101511B4FF801DC
|
||||
:100C700080819181A281B381C81AD90AEA0AFB0A4C
|
||||
:100C8000EE81FF81E15DFB4F408051806280738087
|
||||
:100C9000EE81FF81E153FC4F80819181A281B3817C
|
||||
:100CA00053014201881A990AAA0ABB0AC114D10445
|
||||
:100CB000E104F10469F40E94C802F8010081118185
|
||||
:100CC000228133816B017C01C01AD10AE20AF30A46
|
||||
:100CD00088E191E00E948B012981622F70E080E021
|
||||
:100CE00090E04AE00E945E058FE091E00E948B0157
|
||||
:100CF000F101E45FFD4F8081823051F0833029F0B3
|
||||
:100D0000813051F489EF90E005C088E091E002C0A5
|
||||
:100D100080E091E00E948B018101000F111F98017A
|
||||
:100D200021563C4FF90180819181892B11F18EEE82
|
||||
:100D300090E02C833D830E948B012C813D81F90141
|
||||
:100D40006081718180E090E04AE00E945E058AEE59
|
||||
:100D500090E00E948B01F101E45CFD4F80818230C4
|
||||
:100D600029F0833051F482EE90E005C089ED90E0E7
|
||||
:100D700002C08CEC90E00E948B0183EC90E00E941A
|
||||
:100D80008B01C301B2010E94AF058FEB90E00E947E
|
||||
:100D90008B01C501B4010E94AF0589EB90E00E9470
|
||||
:100DA0008B01C701B6010E94AF0585EB90E00E9460
|
||||
:100DB0008B01F801E156FC4F80819181892BA9F0CC
|
||||
:100DC0008FEA90E00E948B01F801E159FC4F6081AD
|
||||
:100DD0007181F801E15CFC4F80819181681B790B86
|
||||
:100DE00080E090E04AE00E945E0581149104A10435
|
||||
:100DF000B10409F46EC00E94530481EA90E00E949D
|
||||
:100E00008B01EE81FF81E152FD4F80819181A281B2
|
||||
:100E1000B3810E811F81015B1A4FF801C080D18020
|
||||
:100E2000E280F380BC01CD016C197D098E099F0918
|
||||
:100E30000E94AF0586E990E00E948B01EE81FF8160
|
||||
:100E4000E157FB4F80819181A281B381F80100813C
|
||||
:100E5000118122813381BC01CD01601B710B820B9A
|
||||
:100E6000930B0E94AF05F894EE81FF81E158FD4F8E
|
||||
:100E70006081718182819381A50194010E943C0F60
|
||||
:100E800078948BE890E02C833D834A835B830E94B7
|
||||
:100E90008B012C813D814A815B81CA01B901279672
|
||||
:100EA0000FB6F894DEBF0FBECDBFDF91CF911F917B
|
||||
:100EB0000F91FF90EF90DF90CF90BF90AF909F90F9
|
||||
:100EC0008F907F906F905F904F903F902F900C94F9
|
||||
:100ED000AF0527960FB6F894DEBF0FBECDBFDF91EA
|
||||
:100EE000CF911F910F91FF90EF90DF90CF90BF9027
|
||||
:100EF000AF909F908F907F906F905F904F903F90BA
|
||||
:100F00002F9008950E94730F1F920F920FB60F92A9
|
||||
:100F100011242F933F934F935F936F937F938F93FE
|
||||
:100F20009F93AF93BF93EF93FF938BEC95E00E9459
|
||||
:100F30000F02FF91EF91BF91AF919F918F917F91A0
|
||||
:100F40006F915F914F913F912F910F900FBE0F9036
|
||||
:100F50001F9018951F920F920FB60F9211242F9386
|
||||
:100F60008F939F93EF93FF93E091DB05F091DC0566
|
||||
:100F70008081E091E105F091E20582FD12C090814F
|
||||
:100F80008091E4058F5F8F732091E505821751F002
|
||||
:100F9000E091E405F0E0E553FA4F958F8093E40586
|
||||
:100FA00001C08081FF91EF919F918F912F910F90C0
|
||||
:100FB0000FBE0F901F9018951F920F920FB60F92B1
|
||||
:100FC00011242F933F938F939F93AF93BF9380915F
|
||||
:100FD000040290910502A0910602B091070230919F
|
||||
:100FE000030223E0230F2D3720F40196A11DB11D2C
|
||||
:100FF00005C026E8230F0296A11DB11D2093030210
|
||||
:101000008093040290930502A0930602B093070216
|
||||
:101010008091080290910902A0910A02B0910B02FE
|
||||
:101020000196A11DB11D8093080290930902A0931F
|
||||
:101030000A02B0930B02BF91AF919F918F913F91A4
|
||||
:101040002F910F900FBE0F901F9018951F920F9227
|
||||
:101050000FB60F9211242F933F934F935F936F938B
|
||||
:101060007F938F939F93AF93BF93EF93FF9382E010
|
||||
:101070000E94D402FF91EF91BF91AF919F918F9108
|
||||
:101080007F916F915F914F913F912F910F900FBE84
|
||||
:101090000F901F9018951F920F920FB60F92112468
|
||||
:1010A0002F933F934F935F936F937F938F939F9370
|
||||
:1010B000AF93BF93EF93FF9381E00E94D402FF911F
|
||||
:1010C000EF91BF91AF919F918F917F916F915F91C0
|
||||
:1010D0004F913F912F910F900FBE0F901F90189539
|
||||
:1010E0001F920F920FB60F9211242F933F934F939D
|
||||
:1010F0005F936F937F938F939F93AF93BF93EF9380
|
||||
:10110000FF9380E00E94D402FF91EF91BF91AF91D5
|
||||
:101110009F918F917F916F915F914F913F912F910F
|
||||
:101120000F900FBE0F901F901895CF93DF93CDB700
|
||||
:10113000DEB7A8970FB6F894DEBF0FBECDBF789488
|
||||
:1011400084B5826084BD84B5816084BD85B58260CC
|
||||
:1011500085BD85B5816085BD80916E00816080937D
|
||||
:101160006E001092810080918100826080938100E6
|
||||
:1011700080918100816080938100809180008160F6
|
||||
:10118000809380008091B10084608093B100809151
|
||||
:10119000B00081608093B00080917A008460809379
|
||||
:1011A0007A0080917A00826080937A0080917A0040
|
||||
:1011B000816080937A0080917A00806880937A00C1
|
||||
:1011C0001092C1000E9467048FEA95E068E1C62E84
|
||||
:1011D000C80ECF8E0E94C8026D877E878F87988B3E
|
||||
:1011E0008BEC95E00E94F901892B09F47CC38BEC10
|
||||
:1011F00095E00E94D7018C32B9F420917E02822FB3
|
||||
:1012000090E0873091050CF06EC32F5F20937E0233
|
||||
:10121000880F991FFC01E459FD4F80917C02909149
|
||||
:101220007D02918380835BC390ED980F9A30B0F478
|
||||
:1012300040917C0250917D029AE0949F9001959F8D
|
||||
:10124000300D1124205331097901E80EF11C87FD7E
|
||||
:10125000FA94F0927D02E0927C0245C39FE9980FD8
|
||||
:101260009A3108F040C3883609F42FC334F481362C
|
||||
:1012700071F0843609F454C130C3823709F479C25D
|
||||
:10128000833709F479C2893609F027C39EC180915A
|
||||
:101290007E02E82FF0E0EE0FFF1FE459FD4F209192
|
||||
:1012A0007C0230917D02318320838F5F80937E02A8
|
||||
:1012B0000E94C8024B015C0160906C0270906D024C
|
||||
:1012C000862D0E9442047C01C3010197479748F490
|
||||
:1012D000F301EC5DFE4F8081882319F028E12E1583
|
||||
:1012E00040F40E94310486E891E00E948B01C30122
|
||||
:1012F00093C580916E0290916F0287011127823011
|
||||
:10130000910581F083309105A9F00197D9F00E94F1
|
||||
:1013100031048BE691E00E948B01C3010E94EC0531
|
||||
:10132000D12C12C0F801E45CFD4F32E0308332E092
|
||||
:10133000D32E0AC0F801E45CFD4F43E0408323E074
|
||||
:10134000D22E02C0DD24D394D301AB54BE4FFD0195
|
||||
:10135000C490A3014F555E4FFA0124912223C9F096
|
||||
:1013600030E0220F331FF901E75BFE4F8591949126
|
||||
:10137000F901E15CFE4F659174913FB7F894FC016F
|
||||
:101380002081C0942C212083FB018081C822C0824F
|
||||
:101390003FBF8091700290917102892B09F442C085
|
||||
:1013A000F301E55DFE4F8491FD012491FA019491D2
|
||||
:1013B0009923C1F1882339F1833091F038F48130D9
|
||||
:1013C000A9F0823001F584B58F7D12C0873091F08D
|
||||
:1013D0008830A1F08430B9F4809180008F7D03C003
|
||||
:1013E000809180008F77809380000DC084B58F77C7
|
||||
:1013F00084BD09C08091B0008F7703C08091B00098
|
||||
:101400008F7D8093B000E92FF0E0EE0FFF1FE15CCD
|
||||
:10141000FE4F859194913FB7F894FC016081262B93
|
||||
:1014200020833FBFF801EC5DFD4FD08280917202B6
|
||||
:1014300090917302009711F0DD24D394FD01A491E3
|
||||
:10144000FA014491442309F4AAC44250E42FF0E085
|
||||
:10145000EE0FFF1FE25EFE4F0190F081E02D208134
|
||||
:10146000A22BA0835091680021E030E001C0220F40
|
||||
:101470004A95EAF7252B20936800F801E45FFD4FB9
|
||||
:10148000D082F801EE0FFF1FE156FC4F918380835D
|
||||
:10149000F801E155FA4F8081082E000C990B861552
|
||||
:1014A000970561F16082F801EC5AFD4F1082000F40
|
||||
:1014B000111F000F111FF801E15DFB4F1082118217
|
||||
:1014C00012821382F801E153FC4F108211821282C2
|
||||
:1014D0001382F801E151FB4F80829182A282B38294
|
||||
:1014E000F801E157FB4F80829182A282B382F8011A
|
||||
:1014F000E15BFA4F80829182A282B38285E591E01E
|
||||
:101500000E948B01B301770C880B990B0E94C205D6
|
||||
:1015100083E591E00E948B018E2D0E940906D2C1C5
|
||||
:1015200080917E02E82FF0E0EE0FFF1FE459FD4F9F
|
||||
:1015300020917C0230917D02318320838F5F8093E4
|
||||
:101540007E0200916C0210916D02802F0E94420475
|
||||
:101550009801215031092731310540F4F801EC5D43
|
||||
:10156000FE4F2081222311F0893128F00E9431049E
|
||||
:101570008BED91E04EC4F801EB54FE4F2491F8013D
|
||||
:10158000EF55FE4FE491EE2309F40EC4E250AE2F66
|
||||
:10159000B0E0AA0FBB1FA25EBE4F0D90BC91A02D64
|
||||
:1015A0003C91209523232C932C91211102C430913E
|
||||
:1015B000680041E050E001C0440FEA95EAF7242FAB
|
||||
:1015C0002095232320936800F4C380917E02E82FA6
|
||||
:1015D000F0E0EE0FFF1FE459FD4F20917C023091A7
|
||||
:1015E0007D02318320838F5F80937E02843028F4D4
|
||||
:1015F0000E94310480E192E063C120916C0230913D
|
||||
:101600006D02C901019780319E4038F00E9431047B
|
||||
:1016100080916C0290916D025BC0A8EEB3E00E94D5
|
||||
:101620005E0F6B017C01609306017093070180934C
|
||||
:101630000801909309010E94C802DC01CB018C0DC6
|
||||
:101640009D1DAE1DBF1D0091C7051091C8052091BD
|
||||
:10165000C9053091CA0580179107A207B30770F436
|
||||
:101660000E94C802C60ED71EE81EF91EC092C7050A
|
||||
:10167000D092C805E092C905F092CA0520916E0289
|
||||
:1016800030916F02C901019780319E4038F00E946D
|
||||
:10169000310480916E0290916F021AC0A8EEB3E0FF
|
||||
:1016A0000E945E0F60930A0170930B0180930C01FE
|
||||
:1016B00090930D01209170023091710221315EE012
|
||||
:1016C000350748F00E9431048091700290917102B8
|
||||
:1016D0000E94B20502C12115310561F0A8EEB3E008
|
||||
:1016E0000E945E0F609300017093010180930201DC
|
||||
:1016F000909303018091720290917302009721F000
|
||||
:1017000090930501809304018CEF91E00E948B017E
|
||||
:1017100060916C0270916D0280E090E04AE00E945E
|
||||
:101720005E058AEF91E00E948B0160916E027091DC
|
||||
:101730006F0280E090E04AE00E945E0588EF91E051
|
||||
:101740000E948B01609170027091710280E090E0C4
|
||||
:101750004AE00E945E0586EF91E00E948B01609155
|
||||
:1017600072027091730280E090E04AE00E945E0590
|
||||
:10177000A9C00E946704B1C08EE792E00E948B016D
|
||||
:101780000E9420040E9453048BE692E00E948B0189
|
||||
:101790006091060170910701809108019091090103
|
||||
:1017A0000E94FC058BE592E00E948B0160910A018A
|
||||
:1017B00070910B0180910C0190910D010E94FC052C
|
||||
:1017C0008BE492E00E948B01609100017091010115
|
||||
:1017D00080910201909103010E94FC058EE392E04A
|
||||
:1017E0000E948B0180910401909105010E94B20535
|
||||
:1017F0000FEA15E0612C712CC62CD801DD908D010B
|
||||
:10180000BFEFDB16D9F19301220F331F220F331FD5
|
||||
:10181000F901E157FB4F4081518162817381F901E8
|
||||
:10182000E151FB4F7F0180819181A281B381F90158
|
||||
:10183000E15DFB4F80809180A280B38048175907FB
|
||||
:101840006A077B0739F40E94C802F7018081918101
|
||||
:10185000A281B38187E392E00E948B016D2DDD0CA4
|
||||
:10186000770B880B990B0E94C20585E392E00E94DA
|
||||
:101870008B018C2D0E9409060E945304FFEF6F1A02
|
||||
:101880007F0A28E16216710409F0B6CF83E292E084
|
||||
:101890000E948B01C090C705D090C805E090C90593
|
||||
:1018A000F090CA050E94C802A7019601261B370BBB
|
||||
:1018B000480B590BCA01B9010E94AF0585E192E0BE
|
||||
:1018C0000E948B010E94530408C00E9453040E948E
|
||||
:1018D000200489E892E00E945B0410927E0210923C
|
||||
:1018E0007D0210927C028091C7059091C805A0915D
|
||||
:1018F000C905B091CA05CD84DE84EF84F888C81A82
|
||||
:10190000D90AEA0AFB0AF7FE2CC080910A019091DD
|
||||
:101910000B01A0910C01B0910D014D855E856F8585
|
||||
:101920007889481B590B6A0B7B0BAFE4B5E0EFEAF3
|
||||
:10193000F5E080E0919197FD0DC00D911D912D91E5
|
||||
:101940003C9113976A017B01C01AD10AE20AF30A9B
|
||||
:10195000F7FE81E01496DF8CDE12ECCF882309F4C9
|
||||
:101960001BC20E94C8026B017C012FEA35E03E8B4E
|
||||
:101970002D8B4FE455E05C874B876FE973E07A87E6
|
||||
:1019800069878FE393E098878F83AFECB3E0BA83E6
|
||||
:10199000A983212C312CED89FE892191FE8BED8BC1
|
||||
:1019A0002CA327FDC2C1F8948101000F111F000F65
|
||||
:1019B000111F980121513B4FD9014D915D916D91BE
|
||||
:1019C0007C91498B5A8B6B8B7C8BF801E157FB4FD9
|
||||
:1019D00040815181628173814DA35EA36FA378A77B
|
||||
:1019E000F801E15DFB4F4080518062807380789404
|
||||
:1019F0004A015B0169897A898B899C89861A970AD1
|
||||
:101A0000A80AB90AA981BA814D915D916D917C9125
|
||||
:101A1000D301C201841B950BA60BB70B8B839C8350
|
||||
:101A2000AD83BE83AB85BC854D915D916D917C91FD
|
||||
:101A30004F8B588F698F7A8F40910A0150910B011B
|
||||
:101A400060910C0170910D014B8F5C8F6D8F7E8FBB
|
||||
:101A5000D701C601841B950BA60BB70B4F89588D78
|
||||
:101A6000698D7A8D841B950BA60BB70BB7FD4FC004
|
||||
:101A70008091040190910501A0E0B0E04B815C8170
|
||||
:101A80006D817E81481759076A077B07F8F08091BE
|
||||
:101A9000000190910101A0910201B091030188150C
|
||||
:101AA0009905AA05BB0590F4809106019091070164
|
||||
:101AB000A0910801B09109014B8D5C8D6D8D7E8DDB
|
||||
:101AC00084179507A607B70709F059C0F894F801DD
|
||||
:101AD000E157FB4FC082D182E282F382F801E151EB
|
||||
:101AE000FB4FC082D182E282F3827894E981FA814D
|
||||
:101AF0004082518262827382A701960169897A8944
|
||||
:101B00008B899C89261B370B480B590B4DC0809144
|
||||
:101B1000060190910701A0910801B0910901B70158
|
||||
:101B2000A601481B590B6A0B7B0BDB01CA014F89CD
|
||||
:101B3000588D698D7A8D841B950BA60BB70BB7FD5D
|
||||
:101B4000F4C08091040190910501A0E0B0E04B81C8
|
||||
:101B50005C816D817E81481759076A077B0708F40D
|
||||
:101B6000E4C08091000190910101A0910201B09127
|
||||
:101B7000030188159905AA05BB0508F0D6C0A981FF
|
||||
:101B8000BA814D925D926D927C921397F8944DA11B
|
||||
:101B90005EA16FA178A5D9014D935D936D937C9360
|
||||
:101BA00013977894A501940187EA92E028A339A3BA
|
||||
:101BB0004AA35BA30E948B01BCA16B2FBB0F770BC9
|
||||
:101BC000880B990B0E94C20584EA92E00E948B0167
|
||||
:101BD000C301B2010E94AF0581EA92E00E948B012D
|
||||
:101BE0006B817C818D819E810E94AF058EE992E0A0
|
||||
:101BF0000E948B0128A139A14AA15BA1CA01B901A8
|
||||
:101C00000E94AF058BE992E00E948B01C701B601EB
|
||||
:101C10000E94C205E985FA8580819181892B11F1A5
|
||||
:101C200088E992E00E948B01C101880F991F9C01F5
|
||||
:101C300021593C4F3901D9016D917C91EF81F88593
|
||||
:101C400080819181681B790B80E090E04AE00E94DE
|
||||
:101C50005E05F894D3018D919C91EF81F885918375
|
||||
:101C6000808378942B813C814D815E81232B242BB2
|
||||
:101C7000252B09F451C085E992E00E948B01A8014F
|
||||
:101C800041525D4F3A01FA0180819181A281B38175
|
||||
:101C9000BC01CD0129893A894B895C89621B730B90
|
||||
:101CA000840B950B0E94AF0582E992E00E948B01A4
|
||||
:101CB000C501B4010E94AF05D3011D921D921D9272
|
||||
:101CC0001C921397E985FA8580819181892B21F1F6
|
||||
:101CD000F89401581D4FD8016D917D918D919C9183
|
||||
:101CE0002B813C814D815E810E943C0FF801108266
|
||||
:101CF00011821282138278948FE892E028A339A38C
|
||||
:101D00004AA35BA30E948B0128A139A14AA15BA130
|
||||
:101D1000CA01B9010E94AF050E945304AB85BC857E
|
||||
:101D2000CD92DD92ED92FC921397BFEF2B1A3B0AF6
|
||||
:101D3000EB85FC853496FC87EB8729853A852E5FF9
|
||||
:101D40003F4F3A8729874F8158854E5F5F4F5887AD
|
||||
:101D50004F8369817A816C5F7F4F7A83698378E1F1
|
||||
:101D60002716310409F017CE8091060190910701E2
|
||||
:101D7000A0910801B0910901CD84DE84EF84F88838
|
||||
:101D80008C0D9D1DAE1DBF1D8093C7059093C8058A
|
||||
:101D9000A093C905B093CA050E9499021BCA0E946C
|
||||
:101DA000310484E691E097CD0E94310484ED91E006
|
||||
:101DB00092CD9927FC01E155FA4F2FEF2083FC01CA
|
||||
:101DC000EC5AFD4F10829C01220F331F220F331F4C
|
||||
:101DD000F901E15DFB4F1082118212821382F90139
|
||||
:101DE000E153FC4F1082118212821382880F991FD7
|
||||
:101DF000FC01E156FC4F11821082FC01E15CFC4FBA
|
||||
:101E000011821082FC01E159FC4F1182108289EC91
|
||||
:101E100091E00E948B01C8010E94EC055ECDEBECC5
|
||||
:101E2000F5E01382128288EE93E0A0E0B0E08483B4
|
||||
:101E30009583A683B78382E191E09183808385ECCB
|
||||
:101E400090E09587848784EC90E09787868780EC84
|
||||
:101E500090E0918B808B81EC90E0938B828B82EC75
|
||||
:101E600090E0958B848B86EC90E0978B868B118E1F
|
||||
:101E7000128E138E148E0895A1E21A2EAA1BBB1B7C
|
||||
:101E8000FD010DC0AA1FBB1FEE1FFF1FA217B30746
|
||||
:101E9000E407F50720F0A21BB30BE40BF50B661F5C
|
||||
:101EA000771F881F991F1A9469F760957095809520
|
||||
:101EB00090959B01AC01BD01CF010895A29FB00197
|
||||
:101EC000B39FC001A39F700D811D1124911DB29F6E
|
||||
:101ED000700D811D1124911D0895EE0FFF1F0590B7
|
||||
:101EE000F491E02D099481E090E0F8940C94780F3F
|
||||
:041EF000F894FFCF94
|
||||
:101EF400D007000001003075000060EA0000000017
|
||||
:101F040000003002AC01F901D701EB0177026B004C
|
||||
:101F14006C006D00000000030405060700090A0BAD
|
||||
:101F24000C000E0F10110000000000000D0A00004C
|
||||
:00000001FF
|
@ -1,464 +0,0 @@
|
||||
/*
|
||||
* Sketch for counting impulses in a defined interval
|
||||
* e.g. for power meters with an s0 interface that can be
|
||||
* connected to an input of an arduino board
|
||||
*
|
||||
* the sketch uses pin change interrupts which can be anabled
|
||||
* for any of the inputs on e.g. an arduino uno or a jeenode
|
||||
*
|
||||
* the pin change Interrupt handling used here
|
||||
* is based on the arduino playground example on PCINT:
|
||||
* http://playground.arduino.cc/Main/PcInt
|
||||
*
|
||||
* Refer to avr-gcc header files, arduino source and atmega datasheet.
|
||||
*/
|
||||
|
||||
/* Pin to interrupt map:
|
||||
* D0-D7 = PCINT 16-23 = PCIR2 = PD = PCIE2 = pcmsk2
|
||||
* D8-D13 = PCINT 0-5 = PCIR0 = PB = PCIE0 = pcmsk0
|
||||
* A0-A5 (D14-D19) = PCINT 8-13 = PCIR1 = PC = PCIE1 = pcmsk1
|
||||
*/
|
||||
|
||||
#include "pins_arduino.h"
|
||||
|
||||
char* version = "ArduCounter V1.0";
|
||||
char* error = "error ";
|
||||
|
||||
/* arduino pins that are typically ok to use
|
||||
* (some are left out because they are used
|
||||
* as reset, serial, led or other things on most boards) */
|
||||
byte allowedPins[20] =
|
||||
{ 0, 0, 0, 3, 4, 5, 6, 7,
|
||||
0, 9, 10, 11, 12, 0,
|
||||
14, 15, 16, 17, 0, 0};
|
||||
|
||||
|
||||
/* Pin change mask for each chip port */
|
||||
volatile uint8_t *port_to_pcmask[] = {
|
||||
&PCMSK0,
|
||||
&PCMSK1,
|
||||
&PCMSK2
|
||||
};
|
||||
|
||||
/* last PIN States to detect individual pin changes in ISR */
|
||||
volatile static uint8_t PCintLast[3];
|
||||
|
||||
|
||||
unsigned long intervalMin = 10000; // default 10 sec
|
||||
unsigned long intervalMax = 120000; // default 2 min
|
||||
|
||||
unsigned long timeNextReport;
|
||||
unsigned long now;
|
||||
|
||||
boolean doReport = false;
|
||||
|
||||
/* index to the following arrays is the internal PCINT pin number, not the arduino
|
||||
* pin number because the PCINT pin number corresponds to the physical ports
|
||||
* and this saves time for mapping to the arduino numbers
|
||||
*/
|
||||
|
||||
/* pin change mode (RISING etc.) as parameter for ISR */
|
||||
byte PCintMode[24];
|
||||
|
||||
/* pin number for PCINT number if active - otherwise -1 */
|
||||
char PCintActivePin[24];
|
||||
|
||||
/* did we get first interrupt yet? */
|
||||
volatile boolean initialized[24];
|
||||
|
||||
/* individual counter for each real pin */
|
||||
volatile unsigned long counter[24];
|
||||
|
||||
/* count at last report to get difference */
|
||||
unsigned long lastCount[24];
|
||||
|
||||
/* millis at first interrupt for current interval
|
||||
* (is also last interrupt of old interval) */
|
||||
volatile unsigned long startTime[24];
|
||||
|
||||
/* millis at last interrupt */
|
||||
volatile unsigned long lastTime[24];
|
||||
|
||||
/* millis at last report
|
||||
* to find out when maxInterval is over
|
||||
* and report has to be done even if
|
||||
* no impulses were counted */
|
||||
unsigned long lastReport[24];
|
||||
|
||||
|
||||
/* max for SplitLine */
|
||||
#define MAXLINEPARTS 5
|
||||
|
||||
String inputString = ""; // a string to hold incoming data
|
||||
boolean newCommand = false; // whether the command string is complete
|
||||
|
||||
String linePart[MAXLINEPARTS];
|
||||
int lineParts = 0;
|
||||
|
||||
|
||||
/* Add a pin to be handled */
|
||||
int AddPin(uint8_t aPin, int mode) {
|
||||
uint8_t pcintPin; // PCINT pin number for the pin to be added (this is used as index for most arrays)
|
||||
volatile uint8_t *pcmask; // pointer to PCMSK0 or 1 or 2 depending on the port corresponding to the pin
|
||||
unsigned long now = millis();
|
||||
|
||||
uint8_t bit = digitalPinToBitMask(aPin); // bit in PCMSK to enable pin change interrupt for this pin (arduino pin number!)
|
||||
uint8_t port = digitalPinToPort(aPin); // port that this pin belongs to for enabling interrupts for the whole port (arduino pin number!)
|
||||
|
||||
if (port == NOT_A_PORT) {
|
||||
return 1;
|
||||
} else { // map port to bit in PCIR register
|
||||
port -= 2;
|
||||
pcmask = port_to_pcmask[port]; // point to PCMSK0 or 1 or 2 depending on the port corresponding to the pin
|
||||
}
|
||||
if (port == 1) { // now calculate the PCINT pin number that corresponds to the arduino pin number
|
||||
pcintPin = aPin - 6; // port 1: PC0-PC5 (A0-A5 or D14-D19) is PCINT 8-13 (PC6 is reset)
|
||||
} else { // arduino numbering continues at D14 since PB6/PB7 are used for other things
|
||||
pcintPin = port * 8 + (aPin % 8); // port 0: PB0-PB5 (D8-D13) is PCINT 0-5 (PB6/PB7 is crystal)
|
||||
} // port 2: PD0-PD7 (D0-D7) is PCINT 16-23
|
||||
|
||||
PCintMode[pcintPin] = mode; // save mode for ISR which uses the pcintPin as index because this is easy to get in ISR
|
||||
PCintActivePin[pcintPin] = aPin; // save real arduino pin number and flag this pin as active for reporting
|
||||
|
||||
initialized[pcintPin] = false; // initialize arrays for this pin
|
||||
counter[pcintPin] = 0;
|
||||
lastCount[pcintPin] = 0;
|
||||
startTime[pcintPin] = now;
|
||||
lastTime[pcintPin] = now;
|
||||
lastReport[pcintPin] = now;
|
||||
|
||||
*pcmask |= bit; // set the pin change interrupt mask through a pointer to PCMSK0 or 1 or 2 depending on the port corresponding to the pin
|
||||
PCICR |= 0x01 << port; // enable the interrupt
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Remove a pin to be handled */
|
||||
int RemovePin(uint8_t aPin) {
|
||||
uint8_t pcintPin;
|
||||
volatile uint8_t *pcmask;
|
||||
uint8_t bit = digitalPinToBitMask(aPin);
|
||||
uint8_t port = digitalPinToPort(aPin);
|
||||
|
||||
if (port == NOT_A_PORT) {
|
||||
return 1;
|
||||
} else {
|
||||
port -= 2;
|
||||
pcmask = port_to_pcmask[port];
|
||||
}
|
||||
if (port == 1) { // see comments at AddPin above
|
||||
pcintPin = port * 8 + (aPin - 14);
|
||||
} else {
|
||||
pcintPin = port * 8 + (aPin % 8);
|
||||
}
|
||||
PCintActivePin[pcintPin] = -1;
|
||||
|
||||
*pcmask &= ~bit; // disable the mask.
|
||||
if (*pcmask == 0) { // if that's the last one, disable the interrupt.
|
||||
PCICR &= ~(0x01 << port);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// common interrupt handler. "port" is the PCINT port number (0-2)
|
||||
static void PCint(uint8_t port) {
|
||||
uint8_t bit;
|
||||
uint8_t curr;
|
||||
uint8_t mask;
|
||||
uint8_t pcintPin;
|
||||
|
||||
// get the pin states for the indicated port.
|
||||
curr = *portInputRegister(port+2); // current pin states at port
|
||||
mask = curr ^ PCintLast[port]; // xor gets bits that are different
|
||||
PCintLast[port] = curr; // store new pin state for next interrupt
|
||||
|
||||
if ((mask &= *port_to_pcmask[port]) == 0) { // mask is pins that have changed. screen out non pcint pins.
|
||||
return; /* no handled pin changed */
|
||||
}
|
||||
|
||||
for (uint8_t i=0; i < 8; i++) {
|
||||
bit = 0x01 << i; // loop over each pin that changed
|
||||
if (bit & mask) { // is pin change interrupt enabled for this pin?
|
||||
pcintPin = port * 8 + i; // pcint pin numbers directly follow the bit numbers, only arduino pin numbers are special
|
||||
|
||||
// count if mode is CHANGE, or if mode is RISING and
|
||||
// the bit is currently high, or if mode is FALLING and bit is low.
|
||||
if ((PCintMode[pcintPin] == CHANGE
|
||||
|| ((PCintMode[pcintPin] == RISING) && (curr & bit))
|
||||
|| ((PCintMode[pcintPin] == FALLING) && !(curr & bit)))) {
|
||||
lastTime[pcintPin] = millis(); // remember time of this impulse in case it will be the last in the interval
|
||||
if (initialized[pcintPin]) {
|
||||
counter[pcintPin]++; // count
|
||||
} else {
|
||||
startTime[pcintPin] = lastTime[pcintPin]; // if this is the first impulse on this pin, remember time as first impulse in interval
|
||||
initialized[pcintPin] = true; // and start counting the next impulse
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SIGNAL(PCINT0_vect) {
|
||||
PCint(0);
|
||||
}
|
||||
SIGNAL(PCINT1_vect) {
|
||||
PCint(1);
|
||||
}
|
||||
SIGNAL(PCINT2_vect) {
|
||||
PCint(2);
|
||||
}
|
||||
|
||||
|
||||
/* split a line read from serial into individual words
|
||||
* and store them in the array lineParts[] */
|
||||
void SplitLine () {
|
||||
int index = 0;
|
||||
int sepPos = 0;
|
||||
lineParts = 0;
|
||||
while (sepPos > -1 && index < inputString.length()) { // as long as a blank was found an not at end of line ...
|
||||
while (inputString.charAt(index) == ' ' // if next char is another blank
|
||||
&& lineParts < MAXLINEPARTS
|
||||
&& index < inputString.length()) index++; // skip more blanks
|
||||
if (index < inputString.length()) {
|
||||
sepPos = inputString.indexOf(' ', index+1); // find next blank after the word?
|
||||
if (sepPos == -1)
|
||||
linePart[lineParts] = inputString.substring(index); // no more blanks -> take rest of string
|
||||
else
|
||||
linePart[lineParts] = inputString.substring(index, sepPos); // more blanks -> take word nefore next blank and go on
|
||||
index = sepPos + 1; // continue looking after last blank
|
||||
lineParts ++;
|
||||
}
|
||||
}
|
||||
for (int i=lineParts; i<MAXLINEPARTS; i++) // clear the rest of the array
|
||||
linePart[i] = "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
void report() {
|
||||
int aPin;
|
||||
unsigned long newCount, countDiff;
|
||||
unsigned long timeDiff, now;
|
||||
now = millis();
|
||||
for (int pcintPin=0; pcintPin<24; pcintPin++) { // go through all observed pins as PCINT pin number
|
||||
aPin = PCintActivePin[pcintPin]; // take saved arduino pin number
|
||||
if (aPin >= 0) { // -1 means pin is not active for reporting
|
||||
newCount = counter[pcintPin]; // get current counter
|
||||
countDiff = newCount - lastCount[pcintPin]; // how many impulses since last report?
|
||||
if (countDiff == 0 &&
|
||||
(now - lastReport[pcintPin] < intervalMax)) // if nothing to report, take next pin
|
||||
continue;
|
||||
if (countDiff > 0) { // if there was an impulse, report
|
||||
timeDiff = lastTime[pcintPin] - startTime[pcintPin]; // time between first and last impulse during interval
|
||||
lastCount[pcintPin] = newCount; // remember current count for next interval
|
||||
startTime[pcintPin] = lastTime[pcintPin]; // time of last impulse in this interval becomes also time of first impulse in next interval
|
||||
} else {
|
||||
timeDiff = now - startTime[pcintPin]; // there was no impulse, but maxInterval is over: show from last impulse to now
|
||||
startTime[pcintPin] = now; // start a new interval for next report - last one will be reported as 0 imulses ...
|
||||
lastTime[pcintPin] = now; // also time of first impulse in next interval
|
||||
}
|
||||
Serial.println((String) "R" + aPin + // report on serial out
|
||||
" C" + newCount +
|
||||
" D" + countDiff +
|
||||
" T" + timeDiff);
|
||||
lastReport[pcintPin] = now; // remember when we reported
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* give status report in between if requested over serial input */
|
||||
void showCmd() {
|
||||
unsigned long newCount;
|
||||
unsigned long countDiff;
|
||||
unsigned long timeDiff;
|
||||
char* pName;
|
||||
|
||||
Serial.println((String) version);
|
||||
Serial.println((String) "Min " + intervalMin);
|
||||
Serial.println((String) "Max " + intervalMax);
|
||||
|
||||
for (int i=0; i<24; i++) {
|
||||
int aPin = PCintActivePin[i];
|
||||
if (aPin != -1) {
|
||||
timeDiff = lastTime[i] - startTime[i];
|
||||
newCount = counter[i];
|
||||
countDiff = newCount - lastCount[i];
|
||||
if (!timeDiff)
|
||||
timeDiff = millis() - startTime[i];
|
||||
Serial.println((String) "PCInt " + i + " aPin " + aPin
|
||||
+ " Cnt " + newCount + " (+" + countDiff
|
||||
+ " ) in " + timeDiff + " Millis");
|
||||
}
|
||||
}
|
||||
Serial.println((String) "Next in " + (timeNextReport - millis()));
|
||||
}
|
||||
|
||||
|
||||
void addCmd() {
|
||||
String pinArg = linePart[1]; // given arduino pin number or name as string
|
||||
String modeArg = linePart[2]; // mode falling, rising or change
|
||||
String pullArg = linePart[3]; // optional pullup
|
||||
int aPin = -1;
|
||||
int mode = RISING; // default
|
||||
|
||||
if (pinArg.charAt(0) == 'D' || pinArg.charAt(0) == 'd')
|
||||
aPin = pinArg.substring(1).toInt(); // arduino pin name starting with a "d"?
|
||||
if (aPin == -1) {
|
||||
aPin = pinArg.toInt(); // interpret string as pin number
|
||||
if (aPin >= 20 || aPin < 1) {
|
||||
Serial.print(error); Serial.println(aPin);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (allowedPins[aPin] == 0) {
|
||||
Serial.print(error); Serial.println(aPin);
|
||||
return;
|
||||
};
|
||||
if (lineParts > 2) {
|
||||
if (modeArg.equalsIgnoreCase("f"))
|
||||
mode = FALLING;
|
||||
else if (modeArg.equalsIgnoreCase("c"))
|
||||
mode = CHANGE;
|
||||
else if (modeArg.equalsIgnoreCase("r"))
|
||||
mode = RISING;
|
||||
else {
|
||||
Serial.print(error); Serial.println(modeArg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pinMode (aPin, INPUT);
|
||||
if (lineParts > 3) {
|
||||
if (pullArg.equalsIgnoreCase("p"))
|
||||
digitalWrite (aPin, HIGH); // enable pullup resistor
|
||||
else {
|
||||
Serial.print(error); Serial.println(pullArg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (AddPin(aPin, mode) == 0) { // call AddPin with arduino pin number
|
||||
Serial.print("added "); Serial.println(aPin);
|
||||
} else {
|
||||
Serial.print(error); Serial.println(pinArg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void removeCmd() {
|
||||
String pinArg = linePart[1]; // given arduino pin number or name as string in first part
|
||||
int aPin = -1;
|
||||
if (pinArg.charAt(0) == 'D' || pinArg.charAt(0) == 'd')
|
||||
aPin = pinArg.substring(1).toInt(); // arduino pin name starting with a "d"?
|
||||
if (aPin == -1) {
|
||||
aPin = pinArg.toInt(); // interpret string as pin number
|
||||
if (aPin >= 20 || aPin < 1) {
|
||||
Serial.print(error); Serial.println(aPin);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (allowedPins[aPin] == 0) {
|
||||
Serial.print(error); Serial.println(aPin);
|
||||
return;
|
||||
};
|
||||
if (RemovePin(aPin) == 0) { // call RemovePin with arduino pin number
|
||||
Serial.println((String)"removed " + aPin);
|
||||
} else {
|
||||
Serial.print(error); Serial.println(pinArg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void intervalCmd() {
|
||||
String timeArgMin = linePart[1];
|
||||
String timeArgMax = linePart[2];
|
||||
int timeMin = timeArgMin.toInt();
|
||||
if (timeMin < 1 || timeMin > 3600) {
|
||||
Serial.print(error); Serial.println(timeArgMin);
|
||||
return;
|
||||
}
|
||||
int timeMax = timeArgMax.toInt();
|
||||
if (timeMax < 1 || timeMax > 3600 || timeMax < timeMin) {
|
||||
Serial.print(error); Serial.println(timeArgMax);
|
||||
return;
|
||||
}
|
||||
intervalMin = (long)timeMin * 1000;
|
||||
intervalMax = (long)timeMax * 1000;
|
||||
if (millis() + intervalMin < timeNextReport)
|
||||
timeNextReport = millis() + intervalMin;
|
||||
}
|
||||
|
||||
|
||||
void doCommand() {
|
||||
SplitLine();
|
||||
if (linePart[0].equals("show")) {
|
||||
showCmd();
|
||||
} else if (linePart[0].equals("add")) {
|
||||
addCmd();
|
||||
} else if (linePart[0].equals("rem")) {
|
||||
removeCmd();
|
||||
} else if (linePart[0].equals("int")) {
|
||||
intervalCmd();
|
||||
} else {
|
||||
Serial.print(error); Serial.println(linePart[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
unsigned long now = millis();
|
||||
for (int pcintPin=0; pcintPin < 24; pcintPin++) {
|
||||
PCintActivePin[pcintPin] = -1; // set all pins to inactive (-1)
|
||||
}
|
||||
timeNextReport = millis() + intervalMin; // time for first output
|
||||
Serial.begin(9600); // initialize serial
|
||||
inputString.reserve(200); // reserve 200 bytes for the inputString
|
||||
interrupts();
|
||||
Serial.println((String) version + " Setup done.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void loop() {
|
||||
now = millis();
|
||||
doReport = false; // check if report nedds to be called
|
||||
if((long)(now - timeNextReport) >= 0)
|
||||
doReport = true; // intervalMin is over
|
||||
else
|
||||
for (byte pcintPin=0; pcintPin<24; pcintPin++)
|
||||
if (PCintActivePin[pcintPin] >= 0)
|
||||
if((long)(now - (lastReport[pcintPin] + intervalMax)) >= 0)
|
||||
doReport = true; // active pin has not been reported for langer than maxInterval
|
||||
if (doReport) {
|
||||
report();
|
||||
timeNextReport = now + intervalMin; // do it again after interval millis
|
||||
}
|
||||
if (newCommand) {
|
||||
doCommand();
|
||||
inputString = "";
|
||||
newCommand = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
SerialEvent occurs whenever a new data comes in the
|
||||
hardware serial RX. This routine is run between each
|
||||
time loop() runs, so using delay inside loop can delay
|
||||
response. Multiple bytes of data may be available.
|
||||
*/
|
||||
void serialEvent() {
|
||||
while (Serial.available()) {
|
||||
char inChar = (char)Serial.read();
|
||||
if (inChar == '\n' or inChar == '\r') {
|
||||
if (inputString.length() > 0)
|
||||
newCommand = true;
|
||||
} else {
|
||||
inputString += inChar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
804
fhem/contrib/arduino/ArduCounter1.8.ino
Executable file
804
fhem/contrib/arduino/ArduCounter1.8.ino
Executable file
@ -0,0 +1,804 @@
|
||||
/*
|
||||
* Sketch for counting impulses in a defined interval
|
||||
* e.g. for power meters with an s0 interface that can be
|
||||
* connected to an input of an arduino board
|
||||
*
|
||||
* the sketch uses pin change interrupts which can be anabled
|
||||
* for any of the inputs on e.g. an arduino uno or a jeenode
|
||||
*
|
||||
* the pin change Interrupt handling used here
|
||||
* is based on the arduino playground example on PCINT:
|
||||
* http://playground.arduino.cc/Main/PcInt
|
||||
*
|
||||
* Refer to avr-gcc header files, arduino source and atmega datasheet.
|
||||
*/
|
||||
|
||||
/* Pin to interrupt map:
|
||||
* D0-D7 = PCINT 16-23 = PCIR2 = PD = PCIE2 = pcmsk2
|
||||
* D8-D13 = PCINT 0-5 = PCIR0 = PB = PCIE0 = pcmsk0
|
||||
* A0-A5 (D14-D19) = PCINT 8-13 = PCIR1 = PC = PCIE1 = pcmsk1
|
||||
*/
|
||||
|
||||
/*
|
||||
Changes:
|
||||
V1.2
|
||||
27.10.16 - use noInterrupts in report()
|
||||
- avoid reporting very short timeDiff in case of very slow impulses after a report
|
||||
- now reporting is delayed if impulses happened only within in intervalSml
|
||||
- reporting is also delayed if less than countMin pulses counted
|
||||
- extend command "int" for optional intervalSml and countMin
|
||||
29.10.16 - allow interval Min >= Max or Sml > Min
|
||||
which changes behavior to take fixed calculation interval instead of timeDiff between pulses
|
||||
-> if intervalMin = intervalMax, counting will allways follow the reporting interval
|
||||
3.11.16 - more noInterrupt blocks when accessing the non byte volatiles in report
|
||||
V1.3
|
||||
4.11.16 - check min pulse width and add more output,
|
||||
- prefix show output with M
|
||||
V1.4
|
||||
10.11.16 - restructure add Cmd
|
||||
- change syntax for specifying minPulseLengh
|
||||
- res (reset) command
|
||||
V1.6
|
||||
13.12.16 - new startup message logic?, newline before first communication?
|
||||
18.12.16 - replace all code containing Strings, new communication syntax and parsing from Jeelink code
|
||||
V1.7
|
||||
2.1.17 - change message syntax again, report time as well, first and last impulse are reported relative to start of intervall
|
||||
not start of reporting intervall
|
||||
V1.8
|
||||
4.1.17 - fixed a missing break in the case statement for pin definition
|
||||
5.1.17 - cleanup debug logging
|
||||
|
||||
ToDo / Ideas:
|
||||
|
||||
new index scheme to save memory:
|
||||
array to map from pcintPin to new index, limit allowed pins.
|
||||
unused pcintpins point to -1 and vomment states arduino pin number
|
||||
insread of allowedPins array use new function from aPin to pcintPin
|
||||
and then look up in new array for index or -1
|
||||
*/
|
||||
|
||||
#include "pins_arduino.h"
|
||||
|
||||
const char versionStr[] PROGMEM = "ArduCounter V1.8";
|
||||
const char errorStr[] PROGMEM = "Error: ";
|
||||
|
||||
#define enablePulseLenChecking 1
|
||||
|
||||
#define SERIAL_SPEED 38400
|
||||
#define MAX_ARDUINO_PIN 24
|
||||
#define MAX_PCINT_PIN 24
|
||||
#define MAX_INPUT_NUM 8
|
||||
|
||||
/* arduino pins that are typically ok to use
|
||||
* (some are left out because they are used
|
||||
* as reset, serial, led or other things on most boards) */
|
||||
byte allowedPins[MAX_ARDUINO_PIN] =
|
||||
{ 0, 0, 0, 3, 4, 5, 6, 7,
|
||||
0, 9, 10, 11, 12, 0,
|
||||
14, 15, 16, 17, 0, 0};
|
||||
|
||||
|
||||
/* Pin change mask for each chip port */
|
||||
volatile uint8_t *port_to_pcmask[] = {
|
||||
&PCMSK0,
|
||||
&PCMSK1,
|
||||
&PCMSK2
|
||||
};
|
||||
|
||||
/* last PIN States to detect individual pin changes in ISR */
|
||||
volatile static uint8_t PCintLast[3];
|
||||
|
||||
unsigned long intervalMin = 30000; // default 30 sec - report after this time if nothing else delays it
|
||||
unsigned long intervalMax = 60000; // default 60 sec - report after this time if it didin't happen before
|
||||
unsigned long intervalSml = 2000; // default 2 secs - continue count if timeDiff is less and intervalMax not over
|
||||
unsigned int countMin = 1; // continue counting if count is less than this and intervalMax not over
|
||||
|
||||
unsigned long timeNextReport;
|
||||
|
||||
/* index to the following arrays is the internal PCINT pin number, not the arduino
|
||||
* pin number because the PCINT pin number corresponds to the physical ports
|
||||
* and this saves time for mapping to the arduino numbers
|
||||
*/
|
||||
|
||||
/* pin change mode (RISING etc.) as parameter for ISR */
|
||||
byte PCintMode[MAX_PCINT_PIN];
|
||||
/* mode for timing pulse length - derived from PCintMode (RISING etc. */
|
||||
byte PulseMode[MAX_PCINT_PIN];
|
||||
|
||||
/* pin number for PCINT number if active - otherwise -1 */
|
||||
char PCintActivePin[MAX_PCINT_PIN];
|
||||
|
||||
/* did we get first interrupt yet? */
|
||||
volatile boolean initialized[MAX_PCINT_PIN];
|
||||
|
||||
/* individual counter for each real pin */
|
||||
volatile unsigned long counter[MAX_PCINT_PIN];
|
||||
/* count at last report to get difference */
|
||||
unsigned long lastCount[MAX_PCINT_PIN];
|
||||
|
||||
#ifdef enablePulseLenChecking
|
||||
/* individual reject counter for each real pin */
|
||||
volatile unsigned int rejectCounter[MAX_PCINT_PIN];
|
||||
unsigned int lastRejCount[MAX_PCINT_PIN];
|
||||
|
||||
/* millis at last interrupt when signal was rising (for filtering with min pulse length) */
|
||||
volatile unsigned long lastPulseStart[MAX_PCINT_PIN];
|
||||
|
||||
/* millis at last interrupt when signal was falling (for filtering with min pulse length) */
|
||||
volatile unsigned long lastPulseEnd[MAX_PCINT_PIN];
|
||||
|
||||
/* minimal pulse length in millis */
|
||||
/* specified instead of rising or falling. isr needs to check change anyway */
|
||||
unsigned int pulseWidthMin[MAX_PCINT_PIN];
|
||||
|
||||
/* sum of pulse lengths for average output */
|
||||
volatile unsigned long pulseWidthSum[MAX_PCINT_PIN];
|
||||
|
||||
/* start of pulse for measuring length */
|
||||
byte pulseWidthStart[MAX_PCINT_PIN];
|
||||
|
||||
#endif
|
||||
|
||||
/* millis at first interrupt for current calculation
|
||||
* (is also last interrupt of old interval) */
|
||||
volatile unsigned long startTime[MAX_PCINT_PIN];
|
||||
|
||||
/* millis at last interrupt */
|
||||
volatile unsigned long lastTime[MAX_PCINT_PIN];
|
||||
|
||||
/* millis at first interrupt in a reporting cycle */
|
||||
volatile unsigned long startTimeRepInt[MAX_PCINT_PIN];
|
||||
|
||||
|
||||
/* millis at last report
|
||||
* to find out when maxInterval is over
|
||||
* and report has to be done even if
|
||||
* no impulses were counted */
|
||||
unsigned long lastReport[MAX_PCINT_PIN];
|
||||
|
||||
unsigned int commandData[MAX_INPUT_NUM];
|
||||
byte commandDataPointer = 0;
|
||||
|
||||
|
||||
int digitalPinToPcIntPin(uint8_t aPin) {
|
||||
uint8_t pcintPin; // PCINT pin number for the pin to be added (index for most arrays)
|
||||
uint8_t port = digitalPinToPort(aPin) - 2; // port that this arduno pin belongs to for enabling interrupts
|
||||
|
||||
if (port == 1) { // now calculate the PCINT pin number that corresponds to the arduino pin number
|
||||
pcintPin = aPin - 6; // port 1: PC0-PC5 (A0-A5 or D14-D19) is PCINT 8-13 (PC6 is reset)
|
||||
} else { // arduino numbering continues at D14 since PB6/PB7 are used for other things
|
||||
pcintPin = port * 8 + (aPin % 8); // port 0: PB0-PB5 (D8-D13) is PCINT 0-5 (PB6/PB7 is crystal)
|
||||
} // port 2: PD0-PD7 (D0-D7) is PCINT 16-23
|
||||
return pcintPin;
|
||||
}
|
||||
|
||||
|
||||
/* Add a pin to be handled */
|
||||
byte AddPinChangeInterrupt(uint8_t aPin) {
|
||||
uint8_t pcintPin; // PCINT pin number for the pin to be added (used as index for most arrays)
|
||||
volatile uint8_t *pcmask; // pointer to PCMSK0 or 1 or 2 depending on the port corresponding to the pin
|
||||
|
||||
uint8_t bit = digitalPinToBitMask(aPin); // bit in PCMSK to enable pin change interrupt for this arduino pin
|
||||
uint8_t port = digitalPinToPort(aPin); // port that this arduno pin belongs to for enabling interrupts
|
||||
|
||||
if (port == NOT_A_PORT)
|
||||
return 0;
|
||||
|
||||
port -= 2;
|
||||
pcmask = port_to_pcmask[port]; // point to PCMSK0 or 1 or 2 depending on the port corresponding to the pin
|
||||
*pcmask |= bit; // set the pin change interrupt mask through a pointer to PCMSK0 or 1 or 2
|
||||
PCICR |= 0x01 << port; // enable the interrupt
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Remove a pin to be handled */
|
||||
byte RemovePinChangeInterrupt(uint8_t aPin) {
|
||||
uint8_t pcintPin;
|
||||
volatile uint8_t *pcmask;
|
||||
|
||||
uint8_t bit = digitalPinToBitMask(aPin);
|
||||
uint8_t port = digitalPinToPort(aPin);
|
||||
|
||||
if (port == NOT_A_PORT)
|
||||
return 0;
|
||||
|
||||
port -= 2;
|
||||
pcmask = port_to_pcmask[port];
|
||||
*pcmask &= ~bit; // disable the mask.
|
||||
if (*pcmask == 0) { // if that's the last one, disable the interrupt.
|
||||
PCICR &= ~(0x01 << port);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PrintErrorMsg() {
|
||||
int len = strlen_P(errorStr);
|
||||
char myChar;
|
||||
for (unsigned char k = 0; k < len; k++) {
|
||||
myChar = pgm_read_byte_near(errorStr + k);
|
||||
Serial.print(myChar);
|
||||
}
|
||||
}
|
||||
|
||||
void printVersion() {
|
||||
int len = strlen_P(versionStr);
|
||||
char myChar;
|
||||
for (unsigned char k = 0; k < len; k++) {
|
||||
myChar = pgm_read_byte_near(versionStr + k);
|
||||
Serial.print(myChar);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
common interrupt handler. "port" is the PCINT port number (0-2)
|
||||
|
||||
do counting and set start / end time of interval.
|
||||
reporting is not triggered from here.
|
||||
|
||||
only here counter[] is modified
|
||||
lastTime[] is set here and in report
|
||||
startTime[] is set in case a pin was not initialized yet and in report
|
||||
*/
|
||||
static void PCint(uint8_t port) {
|
||||
uint8_t bit;
|
||||
uint8_t curr;
|
||||
uint8_t mask;
|
||||
uint8_t pcintPin;
|
||||
unsigned long now = millis();
|
||||
#ifdef enablePulseLenChecking
|
||||
unsigned long len, gap;
|
||||
#endif
|
||||
// get the pin states for the indicated port.
|
||||
curr = *portInputRegister(port+2); // current pin states at port
|
||||
mask = curr ^ PCintLast[port]; // xor gets bits that are different
|
||||
PCintLast[port] = curr; // store new pin state for next interrupt
|
||||
|
||||
if ((mask &= *port_to_pcmask[port]) == 0) // mask is pins that have changed. screen out non pcint pins.
|
||||
return; /* no handled pin changed */
|
||||
|
||||
for (uint8_t i=0; i < 8; i++) {
|
||||
bit = 0x01 << i; // loop over each pin that changed
|
||||
if (bit & mask) { // did this pin change?
|
||||
pcintPin = port * 8 + i; // pcint pin numbers follow the bits, only arduino pin nums are special
|
||||
|
||||
// count if mode is CHANGE, or if RISING and bit is high, or if mode is FALLING and bit is low.
|
||||
if ((PCintMode[pcintPin] == CHANGE
|
||||
|| ((PCintMode[pcintPin] == RISING) && (curr & bit))
|
||||
|| ((PCintMode[pcintPin] == FALLING) && !(curr & bit)))) {
|
||||
#ifdef enablePulseLenChecking
|
||||
if (pulseWidthMin[pcintPin]) { // check minimal pulse length and gap
|
||||
if ( ( (curr & bit) && pulseWidthStart[pcintPin] == RISING)
|
||||
|| (!(curr & bit) && pulseWidthStart[pcintPin] == FALLING)) { // edge does fit defined start
|
||||
lastPulseStart[pcintPin] = now;
|
||||
continue;
|
||||
} else { // End of defined pulse
|
||||
gap = lastPulseStart[pcintPin] - lastPulseEnd[pcintPin];
|
||||
len = now - lastPulseStart[pcintPin];
|
||||
lastPulseEnd[pcintPin] = now;
|
||||
if (len < pulseWidthMin[pcintPin] || gap < pulseWidthMin[pcintPin]) {
|
||||
rejectCounter[pcintPin]++; // pulse too short
|
||||
continue;
|
||||
}
|
||||
pulseWidthSum[pcintPin] += len; // for average calculation
|
||||
}
|
||||
}
|
||||
#endif
|
||||
lastTime[pcintPin] = now; // remember time of in case pulse will be the last in the interval
|
||||
if (!startTimeRepInt[pcintPin]) startTimeRepInt[pcintPin] = now; // time of first impulse in this reporting interval
|
||||
if (initialized[pcintPin]) {
|
||||
counter[pcintPin]++; // count
|
||||
} else {
|
||||
startTime[pcintPin] = lastTime[pcintPin]; // if this is the very first impulse on this pin -> start interval now
|
||||
initialized[pcintPin] = true; // and start counting the next impulse (so far counter is 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
report count and time for pins that are between min and max interval
|
||||
|
||||
lastCount[] is only modified here (count at time of last reporting)
|
||||
lastTime[] is modified here and in ISR - disable interrupts in critcal moments to avoid garbage in var
|
||||
startTime[] is modified only here (or for very first Interrupt in ISR) -> no problem.
|
||||
*/
|
||||
void report() {
|
||||
int aPin;
|
||||
unsigned long count, countDiff;
|
||||
unsigned long timeDiff, now;
|
||||
unsigned long startT, endT;
|
||||
unsigned long avgLen;
|
||||
now = millis();
|
||||
for (int pcintPin=0; pcintPin < MAX_PCINT_PIN; pcintPin++) { // go through all observed pins as PCINT pin number
|
||||
aPin = PCintActivePin[pcintPin]; // take saved arduino pin number
|
||||
if (aPin < 0) continue; // -1 means pin is not active for reporting
|
||||
noInterrupts();
|
||||
startT = startTime[pcintPin];
|
||||
endT = lastTime[pcintPin];
|
||||
count = counter[pcintPin]; // get current counter
|
||||
interrupts();
|
||||
|
||||
timeDiff = endT - startT; // time between first and last impulse during interval
|
||||
countDiff = count - lastCount[pcintPin]; // how many impulses since last report? (works with wrapping)
|
||||
|
||||
if((long)(now - (lastReport[pcintPin] + intervalMax)) >= 0) { // intervalMax is over
|
||||
if ((countDiff >= countMin) && (timeDiff > intervalSml) && (intervalMin != intervalMax)) {
|
||||
// normal procedure
|
||||
lastCount[pcintPin] = count; // remember current count for next interval
|
||||
noInterrupts();
|
||||
startTime[pcintPin] = endT; // time of last impulse in this interval becomes also time of first impulse in next
|
||||
interrupts();
|
||||
} else {
|
||||
// nothing counted or counts happened during a fraction of intervalMin only
|
||||
noInterrupts();
|
||||
lastTime[pcintPin] = now; // don't calculate with last impulse, use now instead
|
||||
startTime[pcintPin] = now; // start a new interval for next report now
|
||||
interrupts();
|
||||
lastCount[pcintPin] = count; // remember current count for next interval
|
||||
timeDiff = now - startT; // special handling - calculation ends now instead of last impulse
|
||||
}
|
||||
} else if((long)(now - (lastReport[pcintPin] + intervalMin)) >= 0) { // minInterval has elapsed
|
||||
if ((countDiff >= countMin) && (timeDiff > intervalSml)) {
|
||||
// normal procedure
|
||||
lastCount[pcintPin] = count; // remember current count for next interval
|
||||
noInterrupts();
|
||||
startTime[pcintPin] = endT; // time of last impulse in this interval becomes also time of first impulse in next
|
||||
interrupts();
|
||||
} else continue; // not enough counted - wait
|
||||
} else continue; // intervalMin not over - wait
|
||||
|
||||
Serial.print(F("R")); // R Report
|
||||
Serial.print(aPin);
|
||||
Serial.print(F(" C")); // C - Count
|
||||
Serial.print(count);
|
||||
Serial.print(F(" D")); // D - Count Diff
|
||||
Serial.print(countDiff);
|
||||
Serial.print(F(" T")); // T - Time
|
||||
Serial.print(timeDiff);
|
||||
Serial.print(F(" N")); // N - now
|
||||
Serial.print((long)now);
|
||||
|
||||
#ifdef enablePulseLenChecking
|
||||
// rejected count ausgeben
|
||||
// evt auch noch average pulse len und gap len
|
||||
if (pulseWidthMin[pcintPin]) { // check minimal pulse length and gap
|
||||
Serial.print(F(" X")); // X Reject
|
||||
Serial.print(rejectCounter[pcintPin] - lastRejCount[pcintPin]);
|
||||
noInterrupts();
|
||||
lastRejCount[pcintPin] = rejectCounter[pcintPin];
|
||||
interrupts();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (countDiff) {
|
||||
Serial.print(F(" F")); // F - first impulse after the one that started the interval
|
||||
Serial.print((long)startTimeRepInt[pcintPin] - startT);
|
||||
Serial.print(F(" L")); // L - last impulse - marking the end of this interval
|
||||
Serial.print((long)endT - startT);
|
||||
startTimeRepInt[pcintPin] = 0;
|
||||
|
||||
#ifdef enablePulseLenChecking
|
||||
if (pulseWidthMin[pcintPin]) {// check minimal pulse length and gap
|
||||
noInterrupts();
|
||||
avgLen = pulseWidthSum[pcintPin] / countDiff;
|
||||
pulseWidthSum[pcintPin] = 0;
|
||||
interrupts();
|
||||
Serial.print(F(" A"));
|
||||
Serial.print(avgLen);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Serial.println();
|
||||
lastReport[pcintPin] = now; // remember when we reported
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* print status for one pin */
|
||||
void showPin(byte pcintPin) {
|
||||
unsigned long newCount;
|
||||
unsigned long countDiff;
|
||||
unsigned long timeDiff;
|
||||
unsigned long avgLen;
|
||||
|
||||
timeDiff = lastTime[pcintPin] - startTime[pcintPin];
|
||||
newCount = counter[pcintPin];
|
||||
countDiff = newCount - lastCount[pcintPin];
|
||||
if (!timeDiff)
|
||||
timeDiff = millis() - startTime[pcintPin];
|
||||
|
||||
Serial.print(F("PCInt pin "));
|
||||
Serial.print(pcintPin);
|
||||
|
||||
Serial.print(F(", iMode "));
|
||||
switch (PCintMode[pcintPin]) {
|
||||
case RISING: Serial.print(F("rising")); break;
|
||||
case FALLING: Serial.print(F("falling")); break;
|
||||
case CHANGE: Serial.print(F("change")); break;
|
||||
}
|
||||
#ifdef enablePulseLenChecking
|
||||
if (pulseWidthMin[pcintPin] > 0) {
|
||||
Serial.print(F(", min len "));
|
||||
Serial.print(pulseWidthMin[pcintPin]);
|
||||
Serial.print(F(" ms"));
|
||||
switch (pulseWidthStart[pcintPin]) {
|
||||
case RISING: Serial.print(F(" rising")); break;
|
||||
case FALLING: Serial.print(F(" falling")); break;
|
||||
}
|
||||
} else {
|
||||
Serial.print(F(", no min len"));
|
||||
}
|
||||
#endif
|
||||
Serial.print(F(", count "));
|
||||
Serial.print(newCount);
|
||||
Serial.print(F(" (+"));
|
||||
Serial.print(countDiff);
|
||||
Serial.print(F(") in "));
|
||||
Serial.print(timeDiff);
|
||||
Serial.print(F(" ms"));
|
||||
#ifdef enablePulseLenChecking
|
||||
// rejected count ausgeben
|
||||
// evt auch noch average pulse len und gap len
|
||||
if (pulseWidthMin[pcintPin]) { // check minimal pulse length and gap
|
||||
Serial.print(F(" Rej "));
|
||||
Serial.print(rejectCounter[pcintPin] - lastRejCount[pcintPin]);
|
||||
}
|
||||
#endif
|
||||
if (countDiff) {
|
||||
Serial.println();
|
||||
Serial.print(F("M first at "));
|
||||
Serial.print((long)startTimeRepInt[pcintPin] - lastReport[pcintPin]);
|
||||
Serial.print(F(", last at "));
|
||||
Serial.print((long)lastTime[pcintPin] - lastReport[pcintPin]);
|
||||
#ifdef enablePulseLenChecking
|
||||
noInterrupts();
|
||||
avgLen = pulseWidthSum[pcintPin] / countDiff;
|
||||
interrupts();
|
||||
Serial.print(F(", avg len "));
|
||||
Serial.print(avgLen);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* give status report in between if requested over serial input */
|
||||
void showCmd() {
|
||||
unsigned long newCount;
|
||||
unsigned long countDiff;
|
||||
unsigned long timeDiff;
|
||||
unsigned long avgLen;
|
||||
char myChar;
|
||||
|
||||
Serial.print(F("M Status: "));
|
||||
printVersion();
|
||||
Serial.println();
|
||||
Serial.print(F("M normal interval "));
|
||||
Serial.println(intervalMin);
|
||||
Serial.print(F("M max interval "));
|
||||
Serial.println(intervalMax);
|
||||
Serial.print(F("M min interval "));
|
||||
Serial.println(intervalSml);
|
||||
Serial.print(F("M min count "));
|
||||
Serial.println(countMin);
|
||||
|
||||
for (byte pcintPin=0; pcintPin < MAX_PCINT_PIN; pcintPin++) {
|
||||
int aPin = PCintActivePin[pcintPin];
|
||||
if (aPin != -1) {
|
||||
timeDiff = lastTime[pcintPin] - startTime[pcintPin];
|
||||
newCount = counter[pcintPin];
|
||||
countDiff = newCount - lastCount[pcintPin];
|
||||
if (!timeDiff)
|
||||
timeDiff = millis() - startTime[pcintPin];
|
||||
Serial.print(F("M pin "));
|
||||
Serial.print(aPin);
|
||||
Serial.print(F(" "));
|
||||
showPin(pcintPin);
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
Serial.print(F("M Next report in "));
|
||||
Serial.print(timeNextReport - millis());
|
||||
Serial.print(F(" Milliseconds"));
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
handle add command.
|
||||
*/
|
||||
void addCmd(unsigned int *values, byte size) {
|
||||
uint8_t pcintPin; // PCINT pin number for the pin to be added (used as index for most arrays)
|
||||
byte mode;
|
||||
unsigned int pw;
|
||||
unsigned long now = millis();
|
||||
|
||||
//Serial.println(F("M Add called"));
|
||||
int aPin = values[0];
|
||||
pcintPin = digitalPinToPcIntPin(aPin);
|
||||
if (aPin >= MAX_ARDUINO_PIN || aPin < 1
|
||||
|| allowedPins[aPin] == 0 || pcintPin > MAX_PCINT_PIN) {
|
||||
PrintErrorMsg();
|
||||
Serial.print(F("Illegal pin specification "));
|
||||
Serial.println(aPin);
|
||||
return;
|
||||
};
|
||||
|
||||
switch (values[1]) {
|
||||
case 2:
|
||||
mode = FALLING;
|
||||
pulseWidthStart[pcintPin] = FALLING;
|
||||
break;
|
||||
case 3:
|
||||
mode = RISING;
|
||||
pulseWidthStart[pcintPin] = RISING;
|
||||
break;
|
||||
case 1:
|
||||
mode = CHANGE;
|
||||
break;
|
||||
default:
|
||||
PrintErrorMsg();
|
||||
Serial.print(F("Illegal pin specification "));
|
||||
Serial.println(aPin);
|
||||
}
|
||||
|
||||
pinMode (aPin, INPUT);
|
||||
if (values[2]) {
|
||||
digitalWrite (aPin, HIGH); // enable pullup resistor
|
||||
}
|
||||
|
||||
#ifdef enablePulseLenChecking
|
||||
PulseMode[pcintPin] = mode; // specified mode also defines pulse level in this case
|
||||
if (values[3] > 0) {
|
||||
pw = values[3];
|
||||
mode = CHANGE;
|
||||
} else {
|
||||
pw = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!AddPinChangeInterrupt(aPin)) { // add Pin Change Interrupt
|
||||
PrintErrorMsg(); Serial.println(F("AddInt"));
|
||||
return;
|
||||
}
|
||||
PCintMode[pcintPin] = mode; // save mode for ISR which uses the pcintPin as index
|
||||
|
||||
#ifdef enablePulseLenChecking
|
||||
pulseWidthMin[pcintPin] = pw; // minimal pulse width in millis, 3 if not specified n add cmd
|
||||
#endif
|
||||
|
||||
if (PCintActivePin[pcintPin] != aPin) { // in case this pin is already active counting
|
||||
PCintActivePin[pcintPin] = aPin; // save real arduino pin number and flag this pin as active for reporting
|
||||
initialized[pcintPin] = false; // initialize arrays for this pin
|
||||
counter[pcintPin] = 0;
|
||||
lastCount[pcintPin] = 0;
|
||||
startTime[pcintPin] = now;
|
||||
lastTime[pcintPin] = now;
|
||||
lastReport[pcintPin] = now;
|
||||
}
|
||||
Serial.print(F("M defined pin "));
|
||||
Serial.print(aPin);
|
||||
Serial.print(F(" "));
|
||||
showPin(pcintPin);
|
||||
Serial.println();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
handle rem command.
|
||||
*/
|
||||
void removeCmd(unsigned int *values, byte size) {
|
||||
uint8_t pcintPin; // PCINT pin number for the pin to be added (used as index for most arrays)
|
||||
int aPin = values[0];
|
||||
pcintPin = digitalPinToPcIntPin(aPin);
|
||||
if (aPin >= MAX_ARDUINO_PIN || aPin < 1
|
||||
|| allowedPins[aPin] == 0 || pcintPin > MAX_PCINT_PIN) {
|
||||
PrintErrorMsg();
|
||||
Serial.print(F("Illegal pin specification "));
|
||||
Serial.println(aPin);
|
||||
return;
|
||||
};
|
||||
|
||||
if (!RemovePinChangeInterrupt(aPin)) {
|
||||
PrintErrorMsg(); Serial.println(F("RemInt"));
|
||||
return;
|
||||
}
|
||||
|
||||
PCintActivePin[pcintPin] = -1;
|
||||
initialized[pcintPin] = false; // reset for next add
|
||||
counter[pcintPin] = 0;
|
||||
lastCount[pcintPin] = 0;
|
||||
#ifdef enablePulseLenChecking
|
||||
pulseWidthMin[pcintPin] = 0;
|
||||
lastRejCount[pcintPin] = 0;
|
||||
rejectCounter[pcintPin] = 0;
|
||||
#endif
|
||||
|
||||
Serial.print(F("M removed "));
|
||||
Serial.println(aPin);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void intervalCmd(unsigned int *values, byte size) {
|
||||
if (size < 4) {
|
||||
PrintErrorMsg();
|
||||
Serial.print(F("size"));
|
||||
Serial.println();
|
||||
return;
|
||||
}
|
||||
if (values[0] < 1 || values[0] > 3600) {
|
||||
PrintErrorMsg(); Serial.println(values[0]);
|
||||
return;
|
||||
}
|
||||
intervalMin = (long)values[0] * 1000;
|
||||
if (millis() + intervalMin < timeNextReport)
|
||||
timeNextReport = millis() + intervalMin;
|
||||
|
||||
if (values[1] < 1 || values[1] > 3600) {
|
||||
PrintErrorMsg(); Serial.println(values[1]);
|
||||
return;
|
||||
}
|
||||
intervalMax = (long)values[1]* 1000;
|
||||
|
||||
if (values[2] > 3600) {
|
||||
PrintErrorMsg(); Serial.println(values[2]);
|
||||
return;
|
||||
}
|
||||
if (values[2] > 0) {
|
||||
intervalSml = (long)values[2] * 1000;
|
||||
}
|
||||
|
||||
if (values[3]> 0) {
|
||||
countMin = values[3];
|
||||
}
|
||||
Serial.print(F("M intervals set to "));
|
||||
Serial.print(values[0]);
|
||||
Serial.print(F(" "));
|
||||
Serial.print(values[1]);
|
||||
Serial.print(F(" "));
|
||||
Serial.print(values[2]);
|
||||
Serial.print(F(" "));
|
||||
Serial.print(values[3]);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void helloCmd() {
|
||||
Serial.println();
|
||||
printVersion();
|
||||
Serial.println(F("Hello"));
|
||||
}
|
||||
|
||||
|
||||
static void HandleSerialPort(char c) {
|
||||
static unsigned int value;
|
||||
|
||||
if (c == ',') {
|
||||
if (commandDataPointer + 1 < MAX_INPUT_NUM) {
|
||||
commandData[commandDataPointer++] = value;
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
else if ('0' <= c && c <= '9') {
|
||||
value = 10 * value + c - '0';
|
||||
}
|
||||
else if ('a' <= c && c <= 'z') {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
commandData[commandDataPointer] = value;
|
||||
addCmd(commandData, ++commandDataPointer);
|
||||
commandDataPointer = 0;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
commandData[commandDataPointer] = value;
|
||||
removeCmd(commandData, ++commandDataPointer);
|
||||
commandDataPointer = 0;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
commandData[commandDataPointer] = value;
|
||||
intervalCmd(commandData, ++commandDataPointer);
|
||||
commandDataPointer = 0;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
setup();
|
||||
commandDataPointer = 0;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
showCmd();
|
||||
commandDataPointer = 0;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
helloCmd();
|
||||
commandDataPointer = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
commandDataPointer = 0;
|
||||
//PrintErrorMsg(); Serial.println();
|
||||
break;
|
||||
}
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
SIGNAL(PCINT0_vect) {
|
||||
PCint(0);
|
||||
}
|
||||
SIGNAL(PCINT1_vect) {
|
||||
PCint(1);
|
||||
}
|
||||
SIGNAL(PCINT2_vect) {
|
||||
PCint(2);
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
unsigned long now = millis();
|
||||
|
||||
for (int pcintPin=0; pcintPin < MAX_PCINT_PIN; pcintPin++) {
|
||||
PCintActivePin[pcintPin] = -1; // set all pins to inactive (-1)
|
||||
initialized[pcintPin] = false; // initialize arrays for this pin
|
||||
counter[pcintPin] = 0;
|
||||
lastCount[pcintPin] = 0;
|
||||
startTime[pcintPin] = now;
|
||||
lastTime[pcintPin] = now;
|
||||
#ifdef enablePulseLenChecking
|
||||
lastPulseStart[pcintPin] = now;
|
||||
lastPulseEnd[pcintPin] = now;
|
||||
pulseWidthMin[pcintPin] = 0;
|
||||
rejectCounter[pcintPin] = 0;
|
||||
lastRejCount[pcintPin] = 0;
|
||||
#endif
|
||||
lastReport[pcintPin] = now;
|
||||
}
|
||||
|
||||
timeNextReport = millis() + intervalMin; // time for first output
|
||||
Serial.begin(SERIAL_SPEED); // initialize serial
|
||||
delay (500);
|
||||
interrupts();
|
||||
Serial.println();
|
||||
printVersion();
|
||||
Serial.println(F("Started"));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Main Loop
|
||||
checks if report should be called because timeNextReport is reached
|
||||
or lastReport for one pin is older than intervalMax
|
||||
timeNextReport is only set here (and when interval is changed / at setup)
|
||||
*/
|
||||
void loop() {
|
||||
unsigned long now = millis();
|
||||
|
||||
if (Serial.available()) {
|
||||
HandleSerialPort(Serial.read());
|
||||
}
|
||||
boolean doReport = false; // check if report nedds to be called
|
||||
if((long)(now - timeNextReport) >= 0) // works fine when millis wraps.
|
||||
doReport = true; // intervalMin is over
|
||||
else
|
||||
for (byte pcintPin=0; pcintPin < MAX_PCINT_PIN; pcintPin++)
|
||||
if (PCintActivePin[pcintPin] >= 0)
|
||||
if((long)(now - (lastReport[pcintPin] + intervalMax)) >= 0)
|
||||
doReport = true; // active pin has not been reported for langer than intervalMax
|
||||
if (doReport) {
|
||||
report();
|
||||
timeNextReport = now + intervalMin; // do it again after intervalMin millis
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user