Нескольно простых вопросов о программировании AVR на Си.

Обсуждаем контроллеры компании Atmel.
Ответить
Родился
Сообщения: 19
Зарегистрирован: Чт янв 14, 2021 10:25:57

Сообщение Lilia »

Спасибо, за комплименты и ценные советы по оформлению. Наглядность моего кода повысилась.

Но прерывание не появилось. Может все таки есть идеи в чем дело?


Насчет МК - эта крошка поражает своими возможностями, но я что-то устала, от отсутствия информации кроме даташита, что-то очень сложно найти.
Мне только славные рыцари с этого форума помогают.
Реклама
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

Lilia, попробуйте отсечь всё лишнее пока для теста. Для начала банально поставить кнопку на PA2, на какой-нибудь другой пин светодиод и попробовать по прерыванию включать-выключать светодиод. Так-то приведенный фрагмент вроде правильный. Судя по ДШ ничего более и не надо для работы прерывания включать вроде бы.
Реклама
Это не хвост, это антенна
Сообщения: 1492
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

Что нужно поставить, чтобы хотя в симуляторе студии погонять attiny1607? У мну xp и семёрка. Какая студия или какое либо другое программное обеспечение от мелкочипов?
Заинтриговали вы меня этой тинькой...

Добавлено after 8 minutes 42 seconds:
Lilia, не спешите опускать руки. Я поглядел в даташит, и у меня уже моск вскипел... Прорвёмся, разберёмся...
Контактная информация:
Грызет канифоль
Аватара пользователя
Сообщения: 270
Зарегистрирован: Вс окт 20, 2019 13:03:56

Сообщение Shuspano »

Небольшой вопросик по AVR СИ.
Надо записать в порт А старшую тетраду, при этом не испортив младшую тетраду порта.
Придумал такое, не знаю правильно или нет:

Код: Выделить всё

temp = (data & 0xF0);  
PORTA = (temp | (PINA & 0x0F));
сэмулировать чтоб посмотреть не знаю как, сразу вставлять в программу - если это неправильно, то это вряд ли будет единственной ошибкой. В общем, межуюсь.
Реклама
Эиком - электронные компоненты и радиодетали
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Shuspano",url="/forum/viewtopic.php?p=4009888#p4009888"]не знаю правильно или нет[/uquote]
Во-первых, не правильно, во-вторых, не помешало бы указать о каких AVR идет речь, потому что на новых для подобных целей есть специальные регистры. Если говорить про старые AVR, то там если пины сконфигурированы как входы, то PORTx включает подтяжки, т.е. если какой-то пин сконфирурирован именно так, то чтение PINx будет возвращать 1, но только до той поры пока ты на вход не повесишь какую-нибудь кнопку и не нажмешь ее, тогда прочитаешь 0, соответственно и запишешь тоже 0... Читать нужно не уровень на входе, а данные защелки, т.е. сам PORTx. Ну и не зря на новых AVR появились дополнительные регистры с атомарным доступом, по нормально на время подобных операций нужно отключать прерывания...
Реклама
Грызет канифоль
Аватара пользователя
Сообщения: 270
Зарегистрирован: Вс окт 20, 2019 13:03:56

Сообщение Shuspano »

Авр старый (тини26), прерываний нет. То есть, если буду читать сам porta то нормально будет?
Реклама
Это не хвост, это антенна
Сообщения: 1492
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

Код: Выделить всё

PORTA = ((temp & 0xF0) | (PORTA & 0x0F));
Изображение
Последний раз редактировалось Demiurg Вс апр 04, 2021 18:14:28, всего редактировалось 1 раз.
Контактная информация:
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

Раз уж заговорили про порты, то подкинули мне на днях новую tiny1614 и вчера я набросал несколько простых классов для работы с портами на С++20, может кому-то будет интересно:
Спойлер

Код: Выделить всё

template<int portBase, uint8_t mask>	
class PortT : PortBase
{
public:
	static auto _inline_ port()  { return (PORT_t*)portBase; }
	static auto _inline_ vport() { return (VPORT_t*)(portNumber * 4); }
		
	static constexpr uint8_t pinsMask = mask;
	static constexpr uint8_t portNumber = (portBase - 0x400) / 0x20;
	
	static void _inline_ write(uint8_t value)
	{
#ifdef DEBUG
		value &= pinsMask;
#endif
		if constexpr(pinsMask == 0xFF)
		{
			vport()->OUT = value;
		}
		else if constexpr(isOnePin())
		{
			if (__builtin_constant_p(value)) 
			{
				vport()->OUT = (value) ? vport()->OUT | pinsMask : vport()->OUT & ~pinsMask;
			}
			else
			{
				vport()->OUT = vport()->OUT & ~pinsMask;
				if (value)	vport()->OUT = vport()->OUT | pinsMask;
			}
		}
		else
		{
			port()->OUTCLR = pinsMask;
			port()->OUTSET = value;
		}
	}

	static uint8_t _inline_ read() { return vport()->IN & pinsMask; }
	static uint8_t _inline_ readOutput() { return vport()->OUT & pinsMask; }

	static void _inline_ set()   
	{ 
		if constexpr(pinsMask == 0xFF)
			vport()->OUT = 0xFF;
		else if constexpr(isOnePin())
			vport()->OUT = vport()->OUT | pinsMask;
		else
			port()->OUTSET = pinsMask;
	}

	static void _inline_ clear() 
	{ 
		if constexpr(pinsMask == 0xFF)
			vport()->OUT = 0;
		else if constexpr(isOnePin())
			vport()->OUT = vport()->OUT & ~pinsMask;
		else
			port()->OUTCLR = pinsMask;
	}

	static void _inline_ toggle() 
	{ 
		if constexpr(isOnePin())
			vport()->IN = vport()->IN | pinsMask; 
		else
			vport()->IN = pinsMask; 
	}

private:
	static bool consteval isOnePin() { return std::popcount(pinsMask) == 1; }
};

template<uint32_t mask> using PortA = PortT<0x400, mask>;
template<uint32_t mask> using PortB = PortT<0x420, mask>;
template<uint32_t mask> using PortC = PortT<0x440, mask>;
Работает это так:
Спойлер

Код: Выделить всё

volatile uint8_t val = 1;   // LDI R24,0x01
                            // STD Y+1,R24  

PortA<0x10> pa1;
pa1.set();          // SBI 0x01,4
pa1.clear();        // CBI 0x01,4

pa1.write(val);     // LDD R24,Y+1
                    // CBI 0x01,4
                    // CPSE R24,R1
                    // SBI 0x01,4

pa1.write(0x10);    // SBI 0x01,4

PortB<0xFF> pb;
pb.set();           // SER R24
                    // OUT 0x05,R24
pb.clear();         // OUT 0x05,R1

PortA<0x0F> pa2;
pa2.set();          // LDI R24,0x0F
                    // STS 0x0405,R24
pa2.clear();        // STS 0x0406,R24
pa2.toggle();       // OUT 0x02,R24
pa2.write(val);     // LDD R25,Y+1
                    // STS 0x0406,R24
                    // STS 0x0405,R25
Все операции атомарные, на макросах такое сделать довольно проблематично...
Встал на лапы
Сообщения: 121
Зарегистрирован: Пт мар 19, 2021 08:58:45

Сообщение kote52 »

Ребята привет! Пытаюсь обуздать АЦП прерывание по переполнению на Тиньке13, что не правильно делаю, или не понимаю что делаю? в протусе PORTB.1 прыгает, выдает меандр, а не должен(( Остальные ведут себя нормально, пока только симуляция в Протусе, в железе не делал.

Код: Выделить всё

Chip type               : ATtiny13
AVR Core Clock frequency: 9,600000 MHz
Memory model            : Tiny
External RAM size       : 0
Data Stack size         : 16
*******************************************************/

#include <tiny13.h>
#include <delay.h>

unsigned int adc0,adc2;
bit flag1,flag2;

#define FIRST_ADC_INPUT 0
#define LAST_ADC_INPUT 2
unsigned int adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1];
// Bandgap Voltage Reference: Off
#define ADC_VREF_TYPE ((0<<REFS0) | (0<<ADLAR))

// ADC interrupt service routine
// with auto input scanning
interrupt [ADC_INT] void adc_isr(void)
{
static unsigned char input_index=0;
// Read the AD conversion result
adc_data[input_index]=ADCW;
// Select next ADC input
if (++input_index > (LAST_ADC_INPUT-FIRST_ADC_INPUT))
   input_index=0;
ADMUX=(FIRST_ADC_INPUT | ADC_VREF_TYPE)+input_index;
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
}

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
TCNT0=0x6A;
adc0=adc_data[0];
adc2=adc_data[2];
}


void reley(void){
     if(adc2>220 && adc2<300) {PORTB.0=1;}
            else {PORTB.0=0;}

     if(adc2>310 && adc2<350) {PORTB.3=1;}
            else {PORTB.3=0;}
            
     if(flag2==0){
        if(adc2 > 400 && adc2 < 460) {flag1=1;PORTB.1=1;}
            else {PORTB.1=0;flag1=0;}
            

        if(adc2 > 490 && adc2 < 515) {flag1=1;PORTB.2=1;}
            else {PORTB.2=0;flag1=0;}
     }
     
     if(flag1==0){
        if(adc0 > 400 && adc0 < 460) {flag2=1;PORTB.1=1;}
            else {PORTB.1=0;flag2=0;}
         
        if(adc0 > 490 && adc0 < 515) {flag2=1;PORTB.2=1;}
            else {PORTB.2=0;flag2=0;}
     } 
}
void main(void)
{
// Crystal Oscillator division factor: 8
#pragma optsize-
CLKPR=(1<<CLKPCE);
CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (1<<CLKPS1) | (1<<CLKPS0);
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port B initialization
// Function: Bit5=In Bit4=In Bit3=Out Bit2=Out Bit1=Out Bit0=Out 
DDRB=(0<<DDB5) | (0<<DDB4) | (1<<DDB3) | (1<<DDB2) | (1<<DDB1) | (1<<DDB0);
// State: Bit5=T Bit4=T Bit3=0 Bit2=0 Bit1=0 Bit0=0 
PORTB=(0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 150,000 kHz
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
// Timer Period: 1 ms
TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
TCCR0B=(0<<WGM02) | (0<<CS02) | (1<<CS01) | (1<<CS00);
TCNT0=0x6A;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (1<<TOIE0);

// ADC initialization
// ADC Clock frequency: 150,000 kHz
// ADC Bandgap Voltage Reference: Off
// ADC Auto Trigger Source: Timer0 Overflow
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
DIDR0|=(0<<ADC0D) | (0<<ADC2D) | (0<<ADC3D) | (0<<ADC1D);
ADMUX=FIRST_ADC_INPUT | ADC_VREF_TYPE;
ADCSRA=(1<<ADEN) | (0<<ADSC) | (1<<ADATE) | (0<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0);
ADCSRB=(1<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);


// Global enable interrupts
#asm("sei")

while (1){
   reley();     
   }
}
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

kote52, замысел опишите, гадать что должна делать ваша программа никто не будет.
Встал на лапы
Сообщения: 121
Зарегистрирован: Пт мар 19, 2021 08:58:45

Сообщение kote52 »

[uquote="NStorm",url="/forum/viewtopic.php?p=4042092#p4042092"]kote52, замысел опишите, гадать что должна делать ваша программа никто не будет.[/uquote]
Простое управление стеклоподъемниками, нажатие кнопок считывается при помощи АЦП, пассажирская дверь дублируется на водительской стороне. Два канала АЦП один для водительской двери - четыре кнопки (две водительское стекло две пассажирское), второй канал для пассажирской двери две кнопки. Сделал два канала ацп для того чтобы, если управляю водительским стеклом была возможность управлять пассажиру его стеклом в этот момент. Но если водитель управляет пассажирским стеклом, пассажир не может управлять его стеклом.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

а 2 канала АЦП зачем? одним нельзя, что-ли, все кнопки опросить? я ж так понимаю, у вас будет резисторный делитель напряжения, сигнал с которого будет поступать на АЦП?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Встал на лапы
Сообщения: 121
Зарегистрирован: Пт мар 19, 2021 08:58:45

Сообщение kote52 »

[uquote="ARV",url="/forum/viewtopic.php?p=4042317#p4042317"]а 2 канала АЦП зачем? одним нельзя, что-ли, все кнопки опросить? я ж так понимаю, у вас будет резисторный делитель напряжения, сигнал с которого будет поступать на АЦП?[/uquote]
Исходил из наличия резисторов и выше описал почему! Так это проблема два канала опросить? Да просто чисто для образования хочу понимать как это делать в первую очередь! Писать код под две нажатые кнопки на разных дверях(водительское стекло вверх пассажирское виз к примеру), чтоб понималось что и куда нажалось и что с этим делать че т сложно и муторно((
Встал на лапы
Сообщения: 121
Зарегистрирован: Пт мар 19, 2021 08:58:45

Сообщение kote52 »

ARV, NStorm, ну так как парни поможете обуздать опрос 2х каналов АЦП или зря писал? :beer:
Родился
Сообщения: 19
Зарегистрирован: Чт янв 14, 2021 10:25:57

Сообщение Lilia »

У меня проблема с тем же Attiny1607.

Надо настроить тики от внешнего генератора (ecs-5032mv-100-cn-tr).
Регистры настройки тиков защищены. Снимаю защиту, изменить делитель получается, а переключить внешний генератор - никак.
Причем если в регистре MCLKCTRLA в режиме отладки натыкать нужные биты - то программа пойдет выполняться. Иначе подвиснет ожидая while.

Подскажите, где же тут собака порылась?

Код: Выделить всё

	CCP = CCP_IOREG_gc; // снять защиту от записи регистров	
	CLKCTRL.MCLKCTRLB = 0x00; //выключаем делитель
			
	CCP = CCP_IOREG_gc; // снять защиту от записи регистров	
	CLKCTRL.MCLKCTRLA = 0x03; //CLKCTRL_CLKSEL_gm; //включаем внешний осциллятор
	while((CLKCTRL.MCLKSTATUS & 0x80) == 0); //ждем включения осциллятора
Вложения
io-gen.jpg
(95.05 КБ) 129 скачиваний
Мудрый кот
Сообщения: 1759
Зарегистрирован: Пт июн 01, 2018 07:28:45

Сообщение parovoZZ »

А бит FUSE.OSCCFG залочен или нет?
Родился
Сообщения: 19
Зарегистрирован: Чт янв 14, 2021 10:25:57

Сообщение Lilia »

Нет, не залочен. Бит FUSE.OSCCFG.OSCLOCK в нуле.
Мудрый кот
Сообщения: 1759
Зарегистрирован: Пт июн 01, 2018 07:28:45

Сообщение parovoZZ »

Так а если выкинуть этот while, МК переключится на внешний такт?
Родился
Сообщения: 19
Зарегистрирован: Чт янв 14, 2021 10:25:57

Сообщение Lilia »

Нет, не переключается.
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Может кому-то будет интересно.

Сегодня провёл сравнение по размеру кода, генерируемого разными версиями avr-gcc:

Проект ampcontrol:
Спойлер

Код: Выделить всё

6.5.0
   text	   data	    bss	    dec	    hex	filename
  31970	     60	   1703	  33733	   83c5	build/ampcontrol_atmega32_st7920.elf
7.5.0
   text	   data	    bss	    dec	    hex	filename
  31636	     60	   1703	  33399	   8277	build/ampcontrol_atmega32_st7920.elf
8.5.0
   text	   data	    bss	    dec	    hex	filename
  31622	     60	   1703	  33385	   8269	build/ampcontrol_atmega32_st7920.elf
9.3.0
   text	   data	    bss	    dec	    hex	filename
  31774	     60	   1703	  33537	   8301	build/ampcontrol_atmega32_st7920.elf
9.4.0
   text	   data	    bss	    dec	    hex	filename
  31774	     60	   1703	  33537	   8301	build/ampcontrol_atmega32_st7920.elf
10.3.0
   text	   data	    bss	    dec	    hex	filename
  31926	     60	   1703	  33689	   8399	build/ampcontrol_atmega32_st7920.elf
11.2.0
   text	   data	    bss	    dec	    hex	filename
  32074	     98	   1703	  33875	   8453	build/ampcontrol_atmega32_st7920.elf
Проект matrixclock:
Спойлер

Код: Выделить всё

6.5.0
Program:  8088 bytes (.text + .data)
Data:     590 bytes (.data + .bss)
7.5.0
Program:  8082 bytes (.text + .data)
Data:     590 bytes (.data + .bss)
8.5.0
Program:  8024 bytes (.text + .data)
Data:     590 bytes (.data + .bss)
9.3.0
Program:  8158 bytes (.text + .data)
Data:     590 bytes (.data + .bss)
9.4.0
Program:  8158 bytes (.text + .data)
Data:     590 bytes (.data + .bss)
10.3.0
Не влезло в 8K на 30 байт
11.2.0
Не влезло в 8K на 38 байт
Вывод такой - вплоть до 8 версии качество оптимизации улучшалось, а потом начало становиться хуже. Ну, или есть какие-то новые тайные опции у компилятора, которые могли бы вернуть размер кода на прежний уровень.

Да, разница между лучшим и худшим вариантом не более 3%, но иногда, когда прошивка уже впритирку подбирается к размеру flash, это может быть существенно.
Контактная информация:
Ответить

Вернуться в «AVR»