--- tags: NHY --- # Project : FuTai VF-Model ## Description :::info In this document, it will only show the soft ware logic for doing this project (cause I dont know how to do hardware :wink:) ::: This is a model controling a VR(Variable Resistor) to change the AD that MCU get then mapping to the PWM register to control Duty cycle of PWM. Is like : <!-- it should be graph here--> VR -> MCU -> PWM Duty there is the things we use as following below: > MCU :robot_face: : PIC16F1936 > VR : 5K Ω > FOSC : 4Mshz > PWM freq: 100hz ## Logic Then to finish the program works, complet the following step below. ### 1. AD capture To capture AD value, we use polling on timer interrupt to do the work. ~~(even the better way is use AD interrupt)~~ Two parts of function : a. TIMER interrupt scanning (2ms) b. evaluate and get average value #### a. TIMER interrupt scanning (~~2~~6ms) Description: 1. select channel (it works when there are many channel) 2. Activate ad scanning 3. After scanning finished, get the value of ADRES(can get full ad val) 4. back to 1. ```c= // timer SFR void AD_SCAN_CALLBACK(void) { if (AD_SAMPLE_STATE == 0) { // select channel ADCON0 = DEF_AD_CH_03; } else if (AD_SAMPLE_STATE == 1) { //Go ADCON0bits.GO = true; } else if (AD_SAMPLE_STATE == 2) { //get AD Adlist.AdValue = ADRES; Adlist.isDone = true; } AD_SAMPLE_STATE++; if (AD_SAMPLE_STATE > 3) { AD_SAMPLE_STATE = 0; } } ``` #### b. evaluate and get average value 1. when ad scanning done => add value to sample count 2. when have AD_COUNT_MAX's Data => get average value of data ```c= // in Main void ADC_CTRL(void) { if (Adlist.isDone) { Adlist.isDone = false; // flag bounce back Adlist.SampleCount ++; // add sample count Adlist.AvgValue = Adlist.AvgValue + Adlist.AdValue; // avg + ad //and for every 10 times, sum it if (Adlist.SampleCount >= AD_COUNT_MAX) { Adlist.SampleCount = 0; Adlist.AvgValue = Adlist.AvgValue / AD_COUNT_MAX; AD1 = Adlist.AdValue; Adlist.AvgValue = 0; } } } ``` ### 2. Set TMR(n)~n=2~ Timer 2 is related to pwm output frquency. ![](https://i.imgur.com/jLg14d6.png) * Here is some information about timer 2 / 4 / 6 Acroding to the formula $$ PWM Period = [(PRx + 1)]* 4 * TOSC *(TMRx Prescale Value) $$ **Note 1: TOSC = 1/FOSC** Then $$ [(PRx + 1)] = PWM Period* \frac{1}{TOSC} * \frac{1}{4} * \frac {1}{(TMRx Prescale Value)} $$ So here is our setting : FOSC : 4mshz TMR2 Prescale val : 64 PWM Period : 1 / 100 ~(100hz)~ Then : $$ PR2 + 1 = 156.25 \\ PR2 + 1 \approx156 \\ PR2 \approx 155 $$ TIMER INFO : > FOSC = 4mhz > prescale level : 64 > PR2 = 155 > TIMER frequency ≈ 100 > ### 3. PWM setting #### Duty cycle $$ Duty\,Cycle\,Ratial = \frac{CCPRxL:CCPxCON<5:4>(DCxB)}{4*(PRx +1)} $$ Then: | Duty Cycle % | CCPRxL:DCXB | | ------------ | ----------- | | 100 | 624 | | 96 | 599 | | 20 | 125 | Acroding to the table, we can get expect value between Duty Cycle and CCPRxL:DCXB. It will list in Table below. ## Table used Exception formula : * Votage -> AD : $$ AD~ex~ = ( V~in~ - V~min~) - \frac {(AD~max~-AD~min~)}{(V~max~ - V~min~)} + AD~min~ $$ AD -> Duty: $$ Duty = ( AD~in~ - AD~min~) - \frac {(Duty~max~-Duty~min~)}{(AD~max~ - AD~min~)} + Duty~min~ $$ | V | AD~exp~ | AD~in~ | PWM~ct~ | label :label: | | ---- | ------- | ------ | -------- | ------------- | | 0.25 | 50 | 50 | 125 | AD~min~ Duty~min~ | | 0.5 | 100.3 | 81 | 151 | | | 0.75 | 150.6 | 128 | 177 | | | 1 | 201 | 186 | 204 | | | 1.25 | 251.3 | 239 | 230 | | | 1.5 | 301.6 | 295 | 257 | | | 1.75 | 352 | 343 | 283 | | | 2.0 | 402.3 | 392 | 309 | | | 2.25 | 452.6 | 443 | 336 | | | 2.5 | 503 | 497 | 362 | | | 2.75 | 553 | 547 | 388 | | | 3.0 | 603 | 599 | 415 | | | 3.25 | 654 | 655 | 441 | | | 3.5 | 704.3 | 706 | 467 | | | 3.75 | 754.6 | 755 | 494 | | | 4 | 805 | 805 | 520 | | | 4.25 | 855.3 | 854 | 546 | | | 4.5 | 905.6 | 908 | 573 | | | 4.75 | 956 | 965 | 599 | AD~max~ Duty~max~ | ## Problem noted ### 1. Case driven Coding system with case driven can easily control with each state **Using :** ```C= enum _DEF_SYS_STATE { DEF_POW_ON, DEF_POW_OFF, } unsigned char STATE_CTRL; void sys() { switch(STATE_CTRL) { case DEF_POW_ON: // do something break; case DEF_POW_ON: // do something break; } } ``` ### 2. Re Opening when pwm on, re turn on the pwm on register will let PWM wave not stable, it will blink like a flash at the raising edge of the wave. **Using: a flag to control entrance to register** ```C= void PWM_ON() { if(is_PWMCONV) { return; } // PWM ON } void PWM_OFF() { if(!is_PWMCONV) { return; } //PWM OFF } ``` ### 3. AD list scan out of bound index When scanning with array, the index out of bound to make resault of caculation changed somtimes. Make sure the index access are all correct to control your array. ## Contect Auther : YUHUA,HU HackMD : @huyuhua email : hu881121@gmail.com