Суть проблемы вот в чем. Решил освоить SPI и связь с дисплеем Nokia 5110. Столкнулся с пропаданием связи в случайные моменты времени – дисплей получает данные от 1 до 10 секунд, после чего контроллер бесконечно долго ждет ответа о пересылке данных.
Для программирования использую ATmega16A-PU c внутренним генератором частоты 8МГц, программатор внутрисхемный USBASP v2.0, Atmel Studio 7, и AVRDUDE.
Более-менее стабильная работа программы возможна при выставлении F_CPU=1000UL и делителе частоты SPI f/128. Кроме того, более стабильная работа устройства наблюдается при подключенном разъеме программатора – дисплей выводил счетчик от 10 секунд до пары минут.
При нормальном F_CPU общение с дисплеем заканчивается после второй команды настройки дисплея. После чего контроллер отправляет по одной команде в 2-10 минут, но в итоге изображения на дисплее все равно нет.
Почитал про необходимость внешнего кварца, установил согласно даташиту, подсоединив ноги на землю через конденсаторы пленочные (50В 15пФ). Микроконтроллер прошивался и работал в целом минут 15, после чего на запросы программатора более никогда не отвечал и программу не выполнял. Что тут можно сделать не так?
Подскажите, пожалуйста, с чем может быть связано подобное поведение (низкие значения F_CPU, большая стабильность при подключенном программаторе, отложенная смерть при подключении кварца)? Устанавливал другой экземпляр микроконтроллера, всё то же самое.
Программный код--Вступление#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <stdlib.h>
unsigned char ii;
unsigned char s,m,h;
int s2,s3,h2,h3,m2,m3;
--Настройки таймера для вывода на экранvoid timer_ini(void)
{
TCCR1B |= (1<<WGM12); // устанавливаем режим СТС (сброс по совпадению)
TIMSK |= (1<<OCIE1A); //устанавливаем бит разрешения прерывания 1ого счетчика по совпадению с OCR1A(H и L)
OCR1AH = 0b00111101; //записываем в регистр число для сравнения
OCR1AL = 0b00001001;
TCCR1B |= (1<<CS11)|(1<<CS10);//установим делитель f/128.
}
--Моргание светодиодом статусаvoid mig(int dl)
{
PORTD |= (1<<PORTD7);
//моргаем светодиодиком в знак выполнения команд
for(ii=0;ii<=(dl/100);ii++)
{
_delay_ms(100);
}
PORTD &= ~(1<<PORTD7);
for(ii=0;ii<=(dl/100);ii++)
{
_delay_ms(100);
}
}
--Передача по SPIvoid senddata(unsigned char snd)
{
SPDR = snd;
while(!(SPSR & (1<<SPIF))){
PORTD |=(1<<PORTD6);//подождем пока данные передадутся и пока посветим диодиком
}
PORTD &= ~(1<<PORTD6);
}
--Подача настроечных команд на дисплейvoid initscr(void)
{
PORTD &= ~((1<<PORTD0)|(1<<PORTD1)|(1<<PORTD2)); //ножки RST, CE(SS), D/C низкий уровень
_delay_ms(1);
//PORTD |= ((1<<PORTD1)|(1<<PORTD2));//сброс SS и RST
PORTD |= (1<<PORTD0);//сброс RST
senddata(0b00100001);// отправка настроечных команд
senddata(0b00010011);
senddata(0b00000100);
senddata(0b11000001);
senddata(0b00100000);
senddata(0b00001100);
PORTD |=(1<<PORTD2); // включим передачу рисовашек
PORTD |= (1<<PORTD1);//сброс SS
}
--Процедура отрисовки символовvoid sendchar(unsigned char str)
{
// в зависимости от символа рисуем его заранее подобранными командами.
switch (str)
{
case ('A') : senddata(0xF8);senddata(0x24);senddata(0x22);senddata(0x24);senddata(0xF8);senddata(0x00); break;
// и так далее каждый символ
}
}
--Вывод на экран строкиvoid sendstr(char str1[])
{
unsigned int n;
// посылаем на экран строки, разбивая их посимвольно
PORTD &= ~(1<<PORTD1); //ножка CE(SS) низкий уровень
for(n=0;str1[n]!='\0';n++)
{
sendchar(str1[n]);
}
PORTD |= (1<<PORTD1);//сброс SS
}
--Очистка экранаvoid clearscr(void)
{
unsigned int n;
// очитсим экран, послав пробел много раз
PORTD &= ~(1<<PORTD1); //ножка CE(SS) низкий уровень
for(n=0;n<=83;n++){
sendchar(' ');
}
PORTD |= (1<<PORTD1);//сброс SS
}
--Настройка SPIvoid initSPI(void)
{
DDRB |= ((1<<PORTB5)|(1<<PORTB7)); //ножки SPI (MOSI и SCK) на выход
PORTB |= ((1<<PORTB5)|(1<<PORTB7)); //низкий уровень
DDRB &= ~(1<<PORTB6);// ножка MISO на вход
SPCR |= ((1<<SPE)|(1<<MSTR)); //Включим шину, объявим ведущим
SPCR |= ((1<<SPR0)|(1<<SPR1));//установим делитель f/128.
SPSR &= ~(1<<SPR0);
DDRD |= 0xFF; // ножки на выход
PORTD &= ~(1<<PORTD7);//выключим диод
}
--Счетчик по прерываниюISR (TIMER1_COMPA_vect)
{ //запустим счетчики часов, минут и секунд
s++;
if (s==60)
{
m++;
s=0;
if(m==60)
{
h++;
m=0;
}
}
// отделим десятки и единицы часов, минут и секунд друг от друга
h2=h/10;
h3=h%10;
m2=m/10;
m3=m%10;
s2=s/10;
s3=s%10;
}
--Главнаяint main(void)
{
timer_ini();
initSPI();
mig(1000); //после выполнения процедуры инициализации таймера и SPI моргнем на секунду
initscr();
mig(300);//после выполнения процедуры инициализации дисплея моргнем быстро три раза
mig(300);
mig(300);
clearscr();
mig(300); // очистим экран и моргнем быстро три раза
mig(300);
mig(300);
// поприветствуем кого-нибудь
sendstr(" ");
sendstr(" Всем ");
sendstr(" привет! ");
sendstr(" ");
sendstr(" -=(o_O)=- ");
sendstr(" ");
_delay_ms(3000);
sei(); // запустим счетчик
while(1)
{
// и каждые полсекунды посылаем на экран текущее время отсчета
sendstr(" ");
sendstr(" ");
sendstr(" ");
switch (h2)
{
case 0: sendstr("0");break;
case 1: sendstr("1");break;
case 2: sendstr("2");break;
case 3: sendstr("3");break;
case 4: sendstr("4");break;
case 5: sendstr("5");break;
case 6: sendstr("6");break;
case 7: sendstr("7");break;
case 8: sendstr("8");break;
case 9: sendstr("9");break;
}
switch (h3)
{
case 0: sendstr("0");break;
case 1: sendstr("1");break;
case 2: sendstr("2");break;
case 3: sendstr("3");break;
case 4: sendstr("4");break;
case 5: sendstr("5");break;
case 6: sendstr("6");break;
case 7: sendstr("7");break;
case 8: sendstr("8");break;
case 9: sendstr("9");break;
}
sendstr(":");
switch (m2)
{
case 0: sendstr("0");break;
case 1: sendstr("1");break;
case 2: sendstr("2");break;
case 3: sendstr("3");break;
case 4: sendstr("4");break;
case 5: sendstr("5");break;
case 6: sendstr("6");break;
case 7: sendstr("7");break;
case 8: sendstr("8");break;
case 9: sendstr("9");break;
}
switch (m3)
{
case 0: sendstr("0");break;
case 1: sendstr("1");break;
case 2: sendstr("2");break;
case 3: sendstr("3");break;
case 4: sendstr("4");break;
case 5: sendstr("5");break;
case 6: sendstr("6");break;
case 7: sendstr("7");break;
case 8: sendstr("8");break;
case 9: sendstr("9");break;
}
sendstr(":");
switch (s2)
{
case 0: sendstr("0");break;
case 1: sendstr("1");break;
case 2: sendstr("2");break;
case 3: sendstr("3");break;
case 4: sendstr("4");break;
case 5: sendstr("5");break;
case 6: sendstr("6");break;
case 7: sendstr("7");break;
case 8: sendstr("8");break;
case 9: sendstr("9");break;
}
switch (s3)
{
case 0: sendstr("0");break;
case 1: sendstr("1");break;
case 2: sendstr("2");break;
case 3: sendstr("3");break;
case 4: sendstr("4");break;
case 5: sendstr("5");break;
case 6: sendstr("6");break;
case 7: sendstr("7");break;
case 8: sendstr("8");break;
case 9: sendstr("9");break;
}
sendstr(" ");
sendstr(" ");
sendstr(" ");
sendstr(" ");
_delay_ms(500);
}
}