Re: Мелкие вопросы по МК-51 а-ка MCS-51, ASM и не только..
Добавлено: Ср сен 09, 2015 22:00:36
Спасибо, это хорошая мысль, мне просто надо дойти до нее самому))
Здесь можно немножко помяукать :)
https://radiokot.ru/forum/
Код: Выделить всё
#include "main.h"
sbit P1_1 = P1^1; /* SFR for P1.1 */
sbit P2_1 = P2^1; /* SFR for P1.1 */
#define PWMPIN P1_1
#define CLOCK 11059000
#define PERIOD1 1
#define PERIOD2 .5
double Q1 = 0.7;
double Q2 = 0.8;
int HIGH1 = ( 65536 * 12) / CLOCK * Q1;//counts of timer's overflows to reach Q1*Period1
int HIGH2 = ( 65536 * 12) / CLOCK * Q2;//counts of timer's overflows to reach Q2*Period2
int HIGH1_temp = 0;
int HIGH2_temp = 0;
int LOW1 = ( 65536 * 12) / CLOCK * (1-Q1);//counts of timer's overflows to reach (1-Q1)*Period1
int LOW2 = ( 65536 * 12) / CLOCK * (1-Q2);//counts of timer's overflows to reach (1-Q2)*Period2
int LOW1_temp = 0;
int LOW2_temp = 0;
bit pwm1_flag = 0;
bit pwm2_flag = 0;
void pwm_setup(void);
void changeDCPWM1(double);
void changeDCPWM2(double);
void delay(int);
void main(void)
{
pwm_setup();
int loops;
delay(10000);
changeDCPWM1(0.6);
changeDCPWM2(0.3);
delay(10000);
for(loops = 0;;loops++)
{
if(loops == 1000) loops = 0;
changeDCPWM1(Q1*loops/1000);
changeDCPWM2(Q1*(1-(loops/1000)));
}
}
void delay(int delay)
{
while(delay--);
}
void pwm_setup(void)
{
TMOD = 0x11;//T0 and T1 in 16bit
EA = 1;//Enable interrupts
ET0 = 1;//Enable T0 overflow interrupts
ET1 = 1;//Enable T1 overflow interrupts
TR0 = 1;//Start T0
TR1 = 1;//Start T1
}
void changeDCPWM1(double newQ1)
{
HIGH1 = ( 65536 * 12) / CLOCK * newQ1;
LOW1 = ( 65536 * 12) / CLOCK * (1-newQ1);
}
void changeDCPWM2(double newQ2)
{
HIGH2 = ( 65536 * 12) / CLOCK * newQ2;
LOW2 = ( 65536 * 12) / CLOCK * (1-newQ2);
}
void timer0/*_isr*/(void) interrupt 1 //event T0 overflow handler
/*Interrupt*/
{
TF0 = 0;//Clear interrupt flag
if(pwm1_flag) //if now PWM1 is "1"
{
HIGH1_temp++;//increase counts of T0 overflows
if(HIGH1_temp >= HIGH1) //if '1' state of PWM1 is reached
{
P1_1 = 0;//PWM '0'
pwm1_flag = 0;//'cause it's '0' state now
HIGH1_temp = 0;
}
//else do nthn and return to counting
}
else //if now PWM1 is "0"
{
LOW1_temp++;//increase counts of T0 overflows
if(LOW1_temp >= LOW1) //if '0' state of PWM1 is reached
{
P1_1 = 1;//PWM '1'
pwm1_flag = 1;//'cause it's '1' state now
LOW1_temp = 0;
}
//else do nthn and return to counting
}
}
void timer1/*_isr*/(void) interrupt 2 //event T0 overflow handler
/*Interrupt*/
{
TF1 = 0;//Clear interrupt flag
if(pwm2_flag) //if now PWM1 is "1"
{
HIGH2_temp++;//increase counts of T0 overflows
if(HIGH2_temp >= HIGH2) //if '1' state of PWM1 is reached
{
P2_1 = 0;//PWM '0'
pwm2_flag = 0;//'cause it's '0' state now
HIGH2_temp = 0;
}
//else do nthn and return to counting
}
else //if now PWM1 is "0"
{
LOW2_temp++;//increase counts of T0 overflows
if(LOW2_temp >= LOW2) //if '0' state of PWM1 is reached
{
P2_1 = 1;//PWM '1'
pwm2_flag = 1;//'cause it's '1' state now
LOW2_temp = 0;
}
//else do nthn and return to counting
}
}Код: Выделить всё
/*------------------------------------------------------------------------
ADUC812.H
Header file for Analog Devices ADuC812 controller.
Rev. 3.0 02nd July 2007
Copyright (c) 1999 - 2007 Keil - An ARM Company
All rights reserved.
------------------------------------------------------------------------*/
/* BYTE Register */
sfr P0 = 0x80;
sfr SP = 0x81;
sfr DPL = 0x82;
sfr DPH = 0x83;
sfr DPP = 0x84;
sfr PCON = 0x87;
sfr TCON = 0x88;
sfr TMOD = 0x89;
sfr TL0 = 0x8A;
sfr TL1 = 0x8B;
sfr TH0 = 0x8C;
sfr TH1 = 0x8D;
sfr P1 = 0x90;
sfr SCON = 0x98;
sfr SBUF = 0x99;
sfr I2CDAT = 0x9A;
sfr I2CADD = 0x9B;
sfr P2 = 0xA0;
sfr IE = 0xA8;
sfr IE2 = 0xA9;
sfr P3 = 0xB0;
sfr IP = 0xB8;
sfr ECON = 0xB9;
sfr ETIM1 = 0xBA; //AR
sfr ETIM2 = 0xBB;
sfr ETIM3 = 0xC4;
sfr EDATA1 = 0xBC;
sfr EDATA2 = 0xBD;
sfr EDATA3 = 0xBE;
sfr EDATA4 = 0xBF;
sfr WDCON = 0xC0;
sfr EADRL = 0xC6;
sfr T2CON = 0xC8;
sfr RCAP2L = 0xCA;
sfr RCAP2H = 0xCB;
sfr TL2 = 0xCC;
sfr TH2 = 0xCD;
sfr PSW = 0xD0;
sfr DMAL = 0xD2;
sfr DMAH = 0xD3;
sfr DMAP = 0xD4;
sfr ADCCON2 = 0xD8;
sfr ADCDATAL = 0xD9;
sfr ADCDATAH = 0xDA;
sfr PSMCON = 0xDF;
sfr ACC = 0xE0;
sfr I2CCON = 0xE8;
sfr DCON = 0xE8;
sfr ADCCON1 = 0xEF;
sfr B = 0xF0;
sfr ADCOFSL = 0xF1;
sfr ADCOFSH = 0xF2;
sfr ADCGAINL = 0xF3;
sfr ADCGAINH = 0xF4;
sfr ADCCON3 = 0xF5;
sfr SPIDAT = 0xF7;
sfr SPICON = 0xF8;
sfr DAC0L = 0xF9;
sfr DAC0H = 0xFA;
sfr DAC1L = 0xFB;
sfr DAC1H = 0xFC;
sfr DACCON = 0xFD;
/* BIT Register..... */
/* TCON */
sbit TF1 = 0x8F;
sbit TR1 = 0x8E;
sbit TF0 = 0x8D;
sbit TR0 = 0x8C;
sbit IE1 = 0x8B;
sbit IT1 = 0x8A;
sbit IE0 = 0x89;
sbit IT0 = 0x88;
/* P1 */
sbit T2EX = 0x91;
sbit T2 = 0x90;
/* SCON */
sbit SM0 = 0x9F;
sbit SM1 = 0x9E;
sbit SM2 = 0x9D;
sbit REN = 0x9C;
sbit TB8 = 0x9B;
sbit RB8 = 0x9A;
sbit TI = 0x99;
sbit RI = 0x98;
/* IE */
sbit EA = 0xAF;
sbit EADC = 0xAE;
sbit ET2 = 0xAD;
sbit ES = 0xAC;
sbit ET1 = 0xAB;
sbit EX1 = 0xAA;
sbit ET0 = 0xA9;
sbit EX0 = 0xA8;
/* P3 */
sbit RD = 0xB7;
sbit WR = 0xB6;
sbit T1 = 0xB5;
sbit T0 = 0xB4;
sbit INT1 = 0xB3;
sbit INT0 = 0xB2;
sbit TXD = 0xB1;
sbit RXD = 0xB0;
/* IP */
sbit PSI = 0xBF;
sbit PADC = 0xBE;
sbit PT2 = 0xBD;
sbit PS = 0xBC;
sbit PT1 = 0xBB;
sbit PX1 = 0xBA;
sbit PT0 = 0xB9;
sbit PX0 = 0xB8;
/* WDCON */
sbit PRE2 = 0xC7;
sbit PRE1 = 0xC6;
sbit PRE0 = 0xC5;
sbit WDR1 = 0xC3;
sbit WDR2 = 0xC2;
sbit WDS = 0xC1;
sbit WDE = 0xC0;
/* T2CON */
sbit TF2 = 0xCF;
sbit EXF2 = 0xCE;
sbit RCLK = 0xCD;
sbit TCLK = 0xCC;
sbit EXEN2 = 0xCB;
sbit TR2 = 0xCA;
sbit CNT2 = 0xC9;
sbit CAP2 = 0xC8;
/* PSW */
sbit CY = 0xD7;
sbit AC = 0xD6;
sbit F0 = 0xD5;
sbit RS1 = 0xD4;
sbit RS0 = 0xD3;
sbit OV = 0xD2;
sbit F1 = 0xD1;
sbit P = 0xD0;
/* ADCCON2 */
sbit ADCI = 0xDF;
sbit DMA = 0xDE;
sbit CCONV = 0xDD;
sbit SCONV = 0xDC;
sbit CS3 = 0xDB;
sbit CS2 = 0xDA;
sbit CS1 = 0xD9;
sbit CS0 = 0xD8;
/* I2CCON */
sbit MDO = I2CCON^7;
sbit MDE = I2CCON^6;
sbit MCO = I2CCON^5;
sbit MDI = I2CCON^4;
sbit I2CM = I2CCON^3;
sbit I2CRS = I2CCON^2;
sbit I2CTX = I2CCON^1;
sbit I2CI = I2CCON^0;
/* DCON */
sbit D1 = DCON^7;
sbit D1EN = DCON^6;
sbit D0 = DCON^5;
sbit D0EN = DCON^3;
/* SPICON */
sbit ISPI = 0xFF;
sbit WCOL = 0xFE;
sbit SPE = 0xFD;
sbit SPIM = 0xFC;
sbit CPOL = 0xFB;
sbit CPHA = 0xFA;
sbit SPR1 = 0xF9;
sbit SPR0 = 0xF8;
Чтобы предотвратить недоразумения укажите используемую модель МК. С точки зрения силлабовских С8051 неясно зачем вообще нужен инвертор. Настройте ногу порта под прерывание по падающему уровню и все. Но если нужен, Ваша схема с транзистором тоже сработает, не забудьте только включить внутреннюю подтяжку у пина порта. Кроме того, элементы ИЛИ-НЕ и И-НЕ превращаются в инвертор при замыкании входов. Наконец, имеется полно микросхем инверторов на дискретной логике.Пока_без_кота писал(а):Подскажите ...
Спасибо, не знал))Ser60 писал(а):... Кроме того, элементы ИЛИ-НЕ и И-НЕ превращаются в инвертор при замыкании входов. ...
Код: Выделить всё
Count_shadow equ 10
Flag_1 equ 20h.0
Flag_2 equ 20h.1
dseg at 8h
Counter:
ds 1
org 21h
Stack:
cseg
jmp Start
org 03h
jmp Sensor_1
org 0Bh
reti
org 13h
jmp Sensor_2
org 1Bh
reti
org 100h
Start:
mov SP,#Stack
Ini:
mov TCON, #00000101b
mov IE, #10000101b
clr Flag_1
clr Flag_2
Main:
mov P0,#11111111b
jbc Flag_1, Up
jbc Flag_2, Down
jmp Main
Up:
mov P0,#00000001b
mov A,P0
Again_Up2:
rl A
call Del_100ms
mov P0,A
jbc Flag_2,Down
jnb P0.7,Again_Up2
djnz Counter,Again_Up2
clr Flag_1 ; Приходиться вот здесь очищать флаг вручную, чтобы цикл Up не начал выполняться опять
jmp Main
Down:
mov P0,#10000000b
mov A,P0
Again_Down2:
rr A
call Del_100ms
mov P0,A
jbc Flag_1,Up
jnb P0.0,Again_Down2
djnz Counter,Again_Down2
clr Flag_2 ; Приходиться вот здесь очищать флаг вручную, чтобы цикл Down не начал выполняться опять
jmp Main
Del_100ms:
MOV R2, #004h
MOV R1, #0A0h
MOV R0, #04Ch
DJNZ R0, $
DJNZ R1, $-4
DJNZ R2, $-8
MOV R0, #049h
DJNZ R0, $
ret
Sensor_1:
clr EA
setb Flag_1
mov Counter,#Count_shadow
setb EA
reti
Sensor_2:
clr EA
setb Flag_2
mov Counter,#Count_shadow
setb EA
reti
end
Значит где-то намутилось с наложением прерываний.Пока_без_кота писал(а): И подскажите еще такой вопрос. Почему команда jbc может не всегда сбрасывать бит после его проверки и перед переходом на метку ?
...
Проблема в том, что в главном цикле я использую переход к ветке по команде jbc, и флаг при этом должен автоматически сбрасываться. Но он не всегда сбрасывается с первого раза, тоесть иногда (закономерности нет) совершается повторный прогон ветки, как будто флаг не сбросился. Если в конце ветки вручную сбросить флаг командой clr Flag_1(2), то все ок, ненужных повторов не наблюдается.
Код: Выделить всё
void timer0(void) interrupt 1 //event T0 overflow handler
void timer1(void) interrupt 3 //event T1 overflow handler
void timer2(void) interrupt 5 //event T2 overflow handlerНе подскажите, как лучше это продотвратить? Запрещать прерыванияв в цикле Again_Up2 нельзя((Ser60 писал(а): ... Насчет флагов - пока крутитесь в цикле Again_Up2, может произойти прерывание, приводящее к установке бита Flag_1.
Вы "троллите" ,шутите или действительно не догадываетесь ?Пока_без_кота писал(а):Не подскаж-и-ете, как лучше это пр-о-едотвратить? Запрещать прерывания_в в цикле Again_Up2 нельзя..Ser60 писал(а): ... Насчет флагов - пока крутитесь в цикле Again_Up2, может произойти прерывание, приводящее к установке бита Flag_1.
Если нет, опишите словами с максимумом подробностей чего хотите добиться. По коду (и ходу) смахивает на подавление дребезга кнопок с записью чего-то в Р0. Только пока идёт выполнение цикла Again_Up2 и если произойдёт прерывание, то переменная Counter в нём получит иное значение и цикл выполнится уже большее число раз (это важно?). При большом числе прерываний от сенсора 1 код вообще может не выдти из этого цикла. Ещё мне кажется, что флаги Flag_1 и Flag_2 в приведённом фрагменте кода дублируют биты запроса прерываний INT0 и INT1. Тогда зачем вообще нужны эти флаги? Как и вообще, зачем в данном случае нужны прерывания, если у Вас и так в цикле Main производится жёсткий polling ожидания установки флагов.Пока_без_кота писал(а):Если в конце ветки вручную сбросить флаг командой clr Flag_1(2), то все ок, ненужных повторов не наблюдается.
Код: Выделить всё
void timer0(void) interrupt 1 //event T0 overflow handler
void timer1(void) interrupt 3 //event T1 overflow handler
void timer2(void) interrupt 5 //event T2 overflow handlerТретье. Я просто хотел бы построить оптимальный алгоритм. Но раз мои костыли это и так неплохой вариант, то пускай будет.petrenko писал(а):Вы "троллите" ,шутите или действительно не догадываетесь ?![]()
Ну я думал подключить 2 пару сенсоров к другим ногам и параллельно ко входам прерываний, и в обработчике прерывания я проверял бы состояние нужной ноги, и делал бы вывод: если есть просто срабатывание прерывания - значит сработал сенсор 1 лестницы, если есть срабатывание прерывания и при этом нужная нога прижата к земле, значит сработал сенсор 2 лестницы)))Ser60 писал(а):... у Вашего МК всего 2 входа внешнего прерывания. Вам-же нужно обслужить 4 сенсора
В идеале надо бы по 4 сенсора на каждую лестницу (по 2 на каждую сторону, тогда можно бы составить алгоритм подсчета людей в зоне (появляется возможность учета вошедших/вышедших людей). Но это все становится слишком сложно, я решил делать проще. Лестница должна подстраиватся под ПОСЛЕДНИЙ сработавший сенсор. Это самый простой из универсальных алгоритмов. При этом алгоритме невозможна ситауция, что человек вошел, а контроллер подумал, что он вышел и все потушил. Лестница подстраивается под последнего вошедшего, ведь ему дольше всего по ней идти (при условии одинаковой скорости конечноSer60 писал(а): ...что должно быть если свет на лестнице включится и с другого ее конца зайдет навстречу первому другой человек?
И что должно быть если человек зашел на лестницу, свет включился, но не дойдя до второго сенсора человек передумал и повернул обратно?