Подпрограмма для работы с последовательным интерфейсом SPI_READ является точной противоположностью подпрограммы SPI_WRITE, код которой был приведен в Программе 12.1, и реализует следующий алгоритм:
1. Выставить на SCK НИЗКИЙ уровень.
2. COUNT = 8.
3. ПОКА COUNT > 0, ВЫПОЛНЯТЬ:
а) Сформировать на линии SCK импульс
б) Сдвинуть содержимое регистра DATA_IN на один бит влево.
в) Скопировать значение с вывода SDI в старший бит регистра DATA_IN.
г) Декрементировать COUNT.
Этот алгоритм похож на приведенный ранее (см. стр. 371), за исключением того, что регистр DATA_IN сдвигается влево, а состояние вывода SDI становится значением 0-го бита. После восьмого цикла «такт — сдвиг — проверка» содержимое регистра DATA_IN представляет собой байт данных, считанный с последовательного порта. При этом первый принятый бит окажется старшим битом итогового значения.
Подпрограмма SPI_READ, текст которой приведен в Программе 12.3, похожа на подпрограмму вывода SPI_WRITE из Программы 12.1. И их действительно можно объединить для того, чтобы одновременно передавать и принимать данные. Такой тип обмена называется
; ***********************
; * ФУНКЦИЯ: Побитно принимает байт данных, начиная со старшего бита *
; * ВХОД: Нет *
; * ВЫХОД: Принятый байт в DATA_IN; COUNT = 0 *
; ***********************
; Задача 1: Выставляем на SCK НИЗКИЙ уровень
SPI_READ
bcf PORTA,SCK; В режиме ожидания на линии SCK — НИЗКИЙ уровень
; Задача 2: COUNT=8
movlw 8; Инициализируем счетчик цикла
movwf COUNT
; Задача 3: ПОКА COUNT>0, ВЫПОЛНЯТЬ:
; Задача 3,
SER_IN_LOOP
bsf PORTA,SCK
bcf PORTA,SCK
; Задача 3,
bcf STATUS,С; Обнуляем флаг переноса
rlf DATA_IN,f; Сдвигаем байт влево
; Задача 3,
btf sc PORTA,SDI ; Пропускаем, ЕСЛИ SDI == 0
bsf DATA_IN,0; ИНАЧЕ заносим в 0-й бит 1
; Задача 3,
decfsz COUNT,f; Декрементируем счетчик
goto SER_IN_LOOP; и повторяем, пока он не станет равным 0
return
Си-вариант подпрограммы, приведенный в Программе 12.4, использует тот же алгоритм, что и его ассемблерный предшественник. Обратите внимание, как для установки 0-го бита переменной DATA_IN используется Си-оператор ИЛИ (|) с константой Ь’00000001’. Аналогично, операция И с константой b’11111110’ сбрасывает 0-й бит. В компиляторе CCS имеются специальные нестандартные функции bset (DATA__IN, 0) и bclr (DATA_IN, 0), которые можно использовать для установки или сброса любого бита переменной и которые при необходимости изменения единственного бита часто более эффективны, чем использование логических операторов.
unsigned int spi_read()
{
int k;
for(k=0;k<8;k++) /* Повторяем 8 раз */
{
SCK =1; /* Формируем тактовый импульс, по которому */
SCK =0; /* ведомый передает бит на SDI */
DATA_IN = DATA_IN <<1; /* Сдвигаем на один бит влево */
if(SDI)
{DATA_IN = DATA_IN I 0x01;} /* Сбрасываем бит, если SDI =0 */
else
{DATA_IN = DATA_IN & 0xFE;} /* ИНАЧЕ устанавливаем его */
}
return DATA_IN /* Возвращаем принятый байт */
}