Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.
|
Forum Index : Microcontroller and PC projects : Tet another CSUB for capturing digital data with the picomite
Author | Message | ||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 5886 |
Peter started with the LOG CSUB for capturing digital signals. Gerry (disco4now) expanded on that with his Manchester code CSUB. While the original CSUB could be used, I decided to have a go at modifying it to better suit my aims. My C skills are woeful so I pinched bits of both Peters and Gerry's code to make something that works. I have called my effort FETCH. One difference to Peters original is, the timing starts from when the CSUB is called, not from when the picomite started. There are 4 modes, each giving a slightly different sequence of data. This is a comparison of the output from a similar input signal. mode 0 mode 1 mode 2 mode 3 174 200 207 194 -585 609 -410 409 998 1025 415 416 -1418 1445 -420 420 1835 1859 414 413 -2256 2281 -420 421 2664 2691 411 411 -3080 3105 -421 419 3498 3524 412 414 -3916 3941 -417 417 4331 4358 417 418 -4751 4777 -420 419 5166 5193 415 414 -5588 5613 -420 420 5997 6023 411 413 -6338 6364 -350 340 6550 6577 215 212 -6753 6779 -204 202 6967 6993 213 214 -7173 7198 -202 206 7384 7411 213 212 -7587 7614 -205 203 7799 7826 213 213 -8004 8029 -204 204 8216 8243 213 213 The program I used for testing uses the 'Kansas City Tape Standard' Each character takes 37mS and I find a gap between characters of 5mS gives good reliability. Mode 1 is the one I use in the example code while I used mode 2 when setting up the comparitor I used to convert the sine wave to square wave. There I was looking for equal times for each half cycle. Because of the way I use it, the first period is about 200 uS short. That's the time for the Basic code to initiate the CSUB once triggered. The CSUB 'File fetch.bas written 26-09-2022 12:57:31 v1.44 ' FETCH basicarray, samplecount, timeout, mode, nulltime, result ' ' basicarray is an integer array to store the resulting data. It must be at least the size of samplecount. ' samplecount is an integer with the maximum number of samples to record. ' timeout is an integer with the maximum time in microseconds that the csub will run. ' mode is an integer that defines 4 modes (0 - 3) ' mode 0 returns the microseconds since the start of the csub with positive for positive going transitions and negative for negative going transitions. ' mode 1 returns the microseconds since the start of the csub, all are positive numbers. ' mode 2 returns the microseconds since the previous transition, positive for positive going and negative for negative going. ' mode 3 returns the microseconds since the previous transition, all are positive numbers. ' nulltime is an integer giving to time in microseconds without any transition to causee an abort. ' result is an integer variable that returns (hopefully) useful information. ' result will contain a positive number representing the total time in microseconds if the csub ends due to maximum count being reached. ' result will return a negative number representing the remaining samples not read dif the csun times out. CSUB FETCH 00000089 'check_timer B084B5B0 4B21AF00 3320681B 4B1F60FB 3330681B 4B1D60BB 3340681B 4B1B607B 3370681B 4B1A603B 4798681B 681A68FB 4299685B D101D81A D8174290 681B4B14 687B4798 001C681B 001D2300 681A683B 18A4685B 68BB415D 685B681A 416B1912 D8034299 4290D10E E00BD800 681B4B09 601A2200 681B4B08 601A2200 681B4B07 601A2201 46BD46C0 BDB0B004 1000038C 100003AC 10000388 100003C8 100003D0 'intprog B08EB5B0 4B59AF00 637B681B 681B4B57 633B3310 681B4B55 62FB3330 681B4B53 62BB3340 681B4B51 627B3350 681B4B4F 623B3360 681B4B4D 61FB3370 681B6B7B 6A7B61BB 617B681B 681B4B49 6AFB4798 685B681A 41991A80 000B0002 60FB60BA 681A69FB 68B8685B 1A8068F9 00024199 603A000B 69F9607B 68FB68BA 604B600A 681B6A3B D1162B00 681B4B3A 47982009 D0051E03 68BA69B9 600A68FB E00A604B 68FB68BA 21002000 41991A80 000B0002 600A69B9 6A3B604B 2B01681B 69B9D104 68FB68BA 604B600A 681B6A3B D1162B02 681B4B28 47982009 D0051E03 683A69B9 600A687B E00A604B 687B683A 21002000 41991A80 000B0002 600A69B9 6A3B604B 2B03681B 69B9D104 687B683A 604B600A 681B6B3B 697B425A 17D20014 601C0015 6B7B605D 3308681B 6B7B001A 6B3B601A 1E5A681B 601A6B3B 681B6B3B DC102B00 68BA6979 600A68FB 4B0B604B 2200681B 4B0A601A 2200681B 4B09601A 2201681B 46C0601A B00E46BD 46C0BDB0 1000038C 100003AC 1000032C 10000388 100003C8 100003D0 'main B08CB580 60F8AF00 607A60B9 4B2E603B 4A2E681B 601A447A 681B4B2D 447A4A2D 4B2D601A 62FB681B 681B4B2B 62BB3310 681B4B29 627B3320 681B4B27 623B3330 681B4B25 61FB3340 681B4B23 61BB3350 681B4B21 617B3360 681B4B1F 613B3370 6AFB68FA 68BB601A 685B681A 601A6ABB 681B4B1A 00024798 6879000B 68496808 414B1812 600A6A79 4B14604B 4798681B 000B0002 600A6A39 6939604B 23002200 604B600A 681A683B 697B685B 6BBB601A 685B681A 601A69FB 69BB6BFA 46C0601A B00C46BD 46C0BD80 100003C8 FFFFFE65 10000388 FFFFFDBB 1000038C 100003AC END CSUB The source code #include "PicoCFunctions.h" // uSecTimer returns a 64-bit integer giving the number of microseconds since system boot // CFuncRam is 256 bytes of RAM that aren't touched by Basic // PinRead gives the status of a pin specified by the number (pin9 = GP6) // CFuncInt1 is the address of a function to be called when a H/W interrupt occurs on COUNT pin 1 // CFuncmSec is the address of a function to be called every millisecond by trhe main clock interrupt // Interrupt is a variable that tells Basic that the INTERRUPT specified in the Basic code has been triggered // // main(basicarray, samplecount, timeout, mode, nulltime, result) // // basicarray is an integer array to store the resulting data. It must be at least the size of samplecount. // samplecount is an integer with the maximum number of samples to record. // timeout is an integer with the maximum time in microseconds that the csub will run. // mode is an integer that defines 4 modes (0 - 3) // mode 0 returns the microseconds since the start of the csub with positive for positive going transitions and negative for negative going transitions. // mode 1 returns the microseconds since the start of the csub, all are positive numbers. // mode 2 returns the microseconds since the previous transition, positive for positive going and negative for negative going. // mode 3 returns the microseconds since the previous transition, all are positive numbers. // nulltime is an integer giving to time in microseconds without any transition to causee an abort. // result is an integer variable that returns (hopefully) useful information. // result will contain a positive number representing the total time in microseconds if the csub ends due to maximum count being reached. // result will return a negative number representing the remaining samples not read dif the csun times out. static void check_timer(void){ //routine called every millisecond unsigned long long int *endtime=(unsigned long long int *)&CFuncRam[8]; unsigned long long int *starttime=(unsigned long long int *)&CFuncRam[12]; unsigned int *ntime=(unsigned int *)&CFuncRam[16]; unsigned long long int *lasttime=( unsigned long long int *)&CFuncRam[28]; if(uSecTimer()>*endtime || uSecTimer()>(*ntime+ *lasttime+ *starttime)){ // timeout triggered CFuncmSec=0; //disable the millisecond interrupt CFuncInt1=0; //disable the H/W pin change interrupt Interrupt=1; //trigger the Basic interrupt } } static void intprog(void){ //routine called every change on GP6 unsigned int *array=(unsigned int *)&CFuncRam[0]; int *count=(int *)&CFuncRam[4]; unsigned long long int *starttime=(unsigned long long int *)&CFuncRam[12]; unsigned int *res=(unsigned int *)&CFuncRam[20]; int *mode=(int *)&CFuncRam[24]; unsigned long long int *lasttime=( unsigned long long int *)&CFuncRam[28]; unsigned long long int nowusec; unsigned long long int thisusec; unsigned int d=*array; unsigned int r=*res; nowusec=uSecTimer()- *starttime; thisusec=nowusec- *lasttime; *lasttime=nowusec; if (*mode==0){ if(PinRead(9))*(long long int *)d=nowusec; else *(long long int *)d= -nowusec; } if (*mode==1){ *(long long int *)d=nowusec; } if (*mode==2){ if(PinRead(9))*(long long int *)d=thisusec; else *(long long int *)d= -thisusec; } if (*mode==3){ *(long long int *)d=thisusec; } *(long long int *)r= -*count; *array=*array+sizeof(long long int); *count=*count-1; //decrement the event counter if(*count<=0){ //count satisfied *(long long int *)r=nowusec; CFuncmSec=0; //disable the millisecond interrupt CFuncInt1=0; //disable the H/W pin change interrupt Interrupt=1; //trigger the Basic interrupt } //if(PinRead(9))*(long long int *)d=uSecTimer(); //else *(long long int *)d=-uSecTimer(); } void main(long long int *basicarray, long long int *samplecount, long long int *timout, long long int *mde,long long int *nulltime,long long int *result){ CFuncInt1=(unsigned int)&intprog; //set up the address for the H/W interrupt CFuncmSec=(unsigned int)&check_timer; //Set up the address for the millisecond timer unsigned int *array=(unsigned int *)&CFuncRam[0]; //get a pointer to a permanent location to store a global pointer to the array int *count=(int *)&CFuncRam[4]; //get a pointer to a permanent location to store the count of the samples required unsigned long long int *endtime=(unsigned long long int *)&CFuncRam[8]; //get a pointer to a permanent location to store the timeout value unsigned long long int *starttime=(unsigned long long int *)&CFuncRam[12]; unsigned int *ntime=(unsigned int *)&CFuncRam[16]; unsigned int *res=(unsigned int *)&CFuncRam[20]; int *mode=(int *)&CFuncRam[24]; unsigned long long int *lasttime=( unsigned long long int *)&CFuncRam[28]; *array=(unsigned int)basicarray; *count=(int)*samplecount; *endtime=uSecTimer()+ *timout; *starttime=uSecTimer(); *lasttime=0; *mode=(int)*mde; *ntime=(unsigned int)*nulltime; *res=(unsigned int)result; } The KCTS sending program ' KCTS TassyJim Sep 2022 OPTION EXPLICIT OPTION DEFAULT INTEGER CONST char_time = 4.0 ' time to wait between characters DIM bit_time! = 3.2 ' should be 3.33 less processing time. DIM bits(10), message$, k$ message$ = "Hello world" sendtxt message$ PAUSE 2000 DO k$ = INKEY$ IF k$ <> "" THEN sendtxt k$ ENDIF LOOP ' these two subs are all thats needed to send text SUB sendtxt txt$ LOCAL n IF LEN(txt$) > 0 THEN FOR n = 1 TO LEN(txt$) sendchar MID$(txt$,n,1) PAUSE char_time NEXT n ENDIF END SUB SUB sendchar ch$ LOCAL n, t!, et! t! = TIMER bits(0) = 0 ' start bit FOR n = 1 TO 8 bits(n) = (ASC(ch$) >>(n-1)) AND 1 ' bits sent lsb first NEXT n bits(9) = 1 ' 2 stop bits bits(10) = 1 FOR n = 0 TO 10 PLAY TONE 1200*(bits(n)+1),1200*(bits(n)+1) ' 0 = 1200, 1 = 2400 PAUSE bit_time! NEXT n PLAY STOP et! = TIMER ' print et!-t!, bit_time! bit_time! = bit_time! + (36.6667-(et!-t!))/11 'adjust bit_time so that the time for all 11 bits = 36.6667 END SUB and the matching receive program. ' KCTS TassyJim Sep 2022 OPTION EXPLICIT OPTION DEFAULT INTEGER DIM bits(10) ' DIM starttime!, midtime!, bt! DIM n, p, done, k$, char$ DIM bit_time! = 3.2 ' should be 3.33 less processing time. CONST bit_bounds = 1200 ' this is the time for two cycles half way between 1200 and 2400 Hz INTERRUPT myint 'set up an interrupt that can be triggered by the CSUB ' p = 1 SETPIN gp15, INTB, startrec SETPIN gp14, DOUT ' used for timing on the CRO SETPIN gp6,CIN,3 'set pin 9 (GP6) to cause a H/W interrupt on both edges ' DIM aa%(200) 'array to receive the timestamps DIM ab%(200) DIM ac%(200) DIM b%=172 'maximum number of transitions to receive DIM c%=36900 'timeout of the CSUB in microseconds DIM d% = 1 ' csub mode DIM e% = 1000 ' no signal timeout DIM f% ' csub result ' DO IF done = 1 THEN ' we have finished receiving a character done = 0 mark 1 ' used for timing measurements char$ = recchar$() PRINT char$; mark 0 ENDIF LOOP SUB startrec SETPIN gp15, OFF ' IF p THEN FETCH aa%(),b%,c%,d%,e%,f% ELSE FETCH ab%(),b%,c%,d%,e%,f% ENDIF END SUB SUB myint 'subroutine that is triggered when the non-blocking CSUB terminates LOCAL INTEGER i LOCAL b, n, char_asc, bt!,offset!, level! ' print f% mark 1 ' pulse for timing with CRO p = 1 - p SETPIN gp15, INTB, startrec IF p THEN MATH add ab%(), 0, ac%() MATH set 0, ab%() ELSE MATH add aa%(), 0, ac%() MATH set 0, aa%() ENDIF mark 0 done = 1 END SUB ' routines used for receiving and decoding KCTS ' parse the array of received timing and extract the 8 bit byte FUNCTION recchar$() LOCAL b, n, char_asc, bt!,offset!, level! 'for n = 0 to 24 'print ac%(n) 'next n bt! = MATH(MAX ac%())/11 ' the 11 bits should take 36.6667 mS but we adjust as required offset! = bt!/1.8 ' take the first sample shortly after half way throug it. FOR n = 4 TO 200 IF ac%(n) = 0 THEN : EXIT FOR : ENDIF IF b > 10 THEN : EXIT FOR : ENDIF IF ac%(n) > offset! THEN level! = ac%(n)-ac%(n-4) IF level! < bit_bounds THEN ' we average over 4 half cycles bits(b) = 1 ELSE bits(b) = 0 ENDIF offset! = offset! + bt! ' advance to the next bit timeslot INC b ENDIF NEXT n FOR n = 8 TO 1 STEP -1 char_asc = (char_asc << 1) + bits(n) ' lsb received first NEXT n recchar$ = CHR$(char_asc) END FUNCTION SUB mark x PIN(gp14) = x END SUB CSUB FETCH 00000089 'check_timer B084B5B0 4B21AF00 3320681B 4B1F60FB 3330681B 4B1D60BB 3340681B 4B1B607B 3370681B 4B1A603B 4798681B 681A68FB 4299685B D101D81A D8174290 681B4B14 687B4798 001C681B 001D2300 681A683B 18A4685B 68BB415D 685B681A 416B1912 D8034299 4290D10E E00BD800 681B4B09 601A2200 681B4B08 601A2200 681B4B07 601A2201 46BD46C0 BDB0B004 1000038C 100003AC 10000388 100003C8 100003D0 'intprog B08EB5B0 4B59AF00 637B681B 681B4B57 633B3310 681B4B55 62FB3330 681B4B53 62BB3340 681B4B51 627B3350 681B4B4F 623B3360 681B4B4D 61FB3370 681B6B7B 6A7B61BB 617B681B 681B4B49 6AFB4798 685B681A 41991A80 000B0002 60FB60BA 681A69FB 68B8685B 1A8068F9 00024199 603A000B 69F9607B 68FB68BA 604B600A 681B6A3B D1162B00 681B4B3A 47982009 D0051E03 68BA69B9 600A68FB E00A604B 68FB68BA 21002000 41991A80 000B0002 600A69B9 6A3B604B 2B01681B 69B9D104 68FB68BA 604B600A 681B6A3B D1162B02 681B4B28 47982009 D0051E03 683A69B9 600A687B E00A604B 687B683A 21002000 41991A80 000B0002 600A69B9 6A3B604B 2B03681B 69B9D104 687B683A 604B600A 681B6B3B 697B425A 17D20014 601C0015 6B7B605D 3308681B 6B7B001A 6B3B601A 1E5A681B 601A6B3B 681B6B3B DC102B00 68BA6979 600A68FB 4B0B604B 2200681B 4B0A601A 2200681B 4B09601A 2201681B 46C0601A B00E46BD 46C0BDB0 1000038C 100003AC 1000032C 10000388 100003C8 100003D0 'main B08CB580 60F8AF00 607A60B9 4B2E603B 4A2E681B 601A447A 681B4B2D 447A4A2D 4B2D601A 62FB681B 681B4B2B 62BB3310 681B4B29 627B3320 681B4B27 623B3330 681B4B25 61FB3340 681B4B23 61BB3350 681B4B21 617B3360 681B4B1F 613B3370 6AFB68FA 68BB601A 685B681A 601A6ABB 681B4B1A 00024798 6879000B 68496808 414B1812 600A6A79 4B14604B 4798681B 000B0002 600A6A39 6939604B 23002200 604B600A 681A683B 697B685B 6BBB601A 685B681A 601A69FB 69BB6BFA 46C0601A B00C46BD 46C0BD80 100003C8 FFFFFE65 10000388 FFFFFDBB 1000038C 100003AC END CSUB I fed the audio output form the sending pico to a comparitor then into the receiving pico. I use two inputs, one to GP6 for the CSUB and linked it to GP15 through a resistor for the trigger. Jim VK7JH MMedit MMBasic Help |
||||
Tinine Guru Joined: 30/03/2016 Location: United KingdomPosts: 1646 |
Is there a tutorial for creating PM CSubs? Craig |
||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 5886 |
This post is where I started: https://www.thebackshed.com/forum/ViewTopic.php?TID=14126&P=1 Jim VK7JH MMedit MMBasic Help |
||||
phil99 Guru Joined: 11/02/2018 Location: AustraliaPosts: 1773 |
Thanks for posting, this looks useful for all sorts of things. |
||||
disco4now Guru Joined: 18/12/2014 Location: AustraliaPosts: 843 |
Thanks Jim, I have added to my collection of code that I can cut and paste from. Gerry Latest F4 Latest H7 |
||||
Print this page |