Arduino和PIC(8位微控制器)之间的SPI信号转换
SPI signal translation between Arduino and PIC(8bit microcontroller)
我正在测试 Arduino UNO 和 PIC16F1(PC16F1827) 之间的 SPI 通信。
这是我的接线和源代码:
MPLAB X IDE 3.55 / XC8 v1.4.1(免费)
#include <xc.h>
#pragma config FOSC = INTOSC // Inner clock
#pragma config WDTE = OFF // Watchdog timer
#pragma config PWRTE = OFF // Power-Up timer
#pragma config MCLRE = ON // MCLR pin
#pragma config CP = OFF // Code protection
#pragma config CPD = OFF // Memory protection
#pragma config BOREN = ON // Brown-out Reset
#pragma config CLKOUTEN = OFF // Outer clock
#pragma config IESO = OFF // Oscillator switchover
#pragma config FCMEN = OFF // Fail-Safe clockmonitor
#pragma config WRT = OFF // Power-up Timer
#pragma config PLLEN = ON // Use 4xPLL
#pragma config STVREN = OFF // Reset when stack error
#pragma config LVP = OFF // Low voltage program
#define _XTAL_FREQ 32000000 // 32MHz
void main(void)
{
// PIC initialization
OSCCON = 0b00110100; // Inner clock = 4Mhz
ANSELA = 0b00000000; // All RA are digital
TRISA = 0b00000001; // RA0 is input
PORTA = 0b00000000; // Initialize RA
// SPI initalization
SDO1SEL = 0; // RB2 sets to SDO pin
SSP1CON1 = 0b00100101; // Slave mode(Unuse SS)
SSP1STAT = 0b01000000; // Slave mode(Clock phase is LOW)
SSP1BUF = 0;
unsigned char read_data; // Current is dummy
unsigned char count = 255;
while(1){
// Read byte from master
read_data = SSP1BUF;
while(!SSP1STATbits.BF);
// Write byte to master
if(count == 255) count = 0; else count++;
SSP1BUF = count;
while(!SSPSTATbits.BF);
}
}
Arduino IDE 1.8.1
#include <SPI.h>
void setup()
{
Serial.begin(9600);
SPI.begin() ;
SPI.setBitOrder(MSBFIRST) ;
SPI.setDataMode(SPI_MODE1) ;
delay(1500) ;
}
void loop()
{
char msg[100];
byte i, n;
for (i = 0 ; i < 10 ; i++) {
n = SPI.transfer(i) ;
sprintf(msg, "%d/%d,", n, i);
Serial.print(msg);
}
Serial.print("\n");
}
我的理想是Arduino接收0-255的值(我忽略了SPI的频率,因为它是一个编程测试)。但是 SPI.transfer() returns 的值为 i(0-9).
网上关于那些IC的技术资料太少了,我很苦恼到底该修哪里。有人知道好方法吗?
我查看了 PIC 16F1826 数据表以检查您的连接。
用于从 SPI1 传输数据的引脚,名为 SDO1,可以是 RA6 或 RB2(来自数据表,第 12 页 [Table 1-2])。
鉴于您将 0 写入 SDO1SEL(复位时它已经为 0),SDO1 似乎在 RB2 上。事实上,你连接的是 RB2 而不是 RA6。
但是您没有清除相应的 TRISB 位以使 RB2 成为输出,如第 236 页(第 25.2.2 章)所述。您当前的程序无法从 RB2/SDO1.
传输数据
也许还有其他错误,可能是在设置寄存器时。我建议仔细阅读数据表并修改 PIC 端的所有设置。然后,如果您还有问题,请更新您的问题,我会更新我的答案(发表评论唤醒我)。例如,我没有检查你从 RB2 连接到 Arduino 的正确位置(我看到它连接到引脚 11,但我没有检查它是否正确:像一些编译器一样,我在第一个错误处停止) .
我固定接线(MISO 到 MISO,MOSI 到 MOSI,连接 SS)。
然后我改了PIC16F1上的程序。它附加初始化 RB 引脚和信号接收作为中断。
unsigned char count = 0;
void interrupt OnInterSpi()
{
if (SSP1IF == HIGH){
SSP1IF = LOW;
unsigned char read_data = SSP1BUF;
if(count == 255) count = 0; else count++;
SSP1BUF = count;
}
}
void main(void)
{
OSCCON = 0b00110100;
ANSELA = 0b00000000;
TRISA = 0b00000001;
PORTA = 0b00000000;
ANSELB = 0b00000000;
TRISB = 0b00010010;
PORTB = 0b00000000;
SDO1SEL = 0;
SSP1CON1 = 0b00100100;
SSP1STAT = 0b01000000;
SSP1IF = 0;
SSP1IE = 1;
PEIE = 1;
GIE = 1;
while(1) ;
}
在 Arduino 上,我启用了 SS 信号。
#include <SPI.h>
#define SS_PIN 10
void setup()
{
Serial.begin(9600);
pinMode(SS_PIN, OUTPUT);
digitalWrite(SS_PIN, HIGH);
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
}
char msg[100];
byte i, n;
void loop()
{
digitalWrite(SS_PIN, LOW);
n = SPI.transfer(i);
digitalWrite(SS_PIN, HIGH);
sprintf(msg, "%d/%d, ", n, i);
Serial.print(msg);
}
至少在我的环境中,在 Arduino 的串行监视器上接收到的值正确增加。
我正在测试 Arduino UNO 和 PIC16F1(PC16F1827) 之间的 SPI 通信。
这是我的接线和源代码:
MPLAB X IDE 3.55 / XC8 v1.4.1(免费)
#include <xc.h>
#pragma config FOSC = INTOSC // Inner clock
#pragma config WDTE = OFF // Watchdog timer
#pragma config PWRTE = OFF // Power-Up timer
#pragma config MCLRE = ON // MCLR pin
#pragma config CP = OFF // Code protection
#pragma config CPD = OFF // Memory protection
#pragma config BOREN = ON // Brown-out Reset
#pragma config CLKOUTEN = OFF // Outer clock
#pragma config IESO = OFF // Oscillator switchover
#pragma config FCMEN = OFF // Fail-Safe clockmonitor
#pragma config WRT = OFF // Power-up Timer
#pragma config PLLEN = ON // Use 4xPLL
#pragma config STVREN = OFF // Reset when stack error
#pragma config LVP = OFF // Low voltage program
#define _XTAL_FREQ 32000000 // 32MHz
void main(void)
{
// PIC initialization
OSCCON = 0b00110100; // Inner clock = 4Mhz
ANSELA = 0b00000000; // All RA are digital
TRISA = 0b00000001; // RA0 is input
PORTA = 0b00000000; // Initialize RA
// SPI initalization
SDO1SEL = 0; // RB2 sets to SDO pin
SSP1CON1 = 0b00100101; // Slave mode(Unuse SS)
SSP1STAT = 0b01000000; // Slave mode(Clock phase is LOW)
SSP1BUF = 0;
unsigned char read_data; // Current is dummy
unsigned char count = 255;
while(1){
// Read byte from master
read_data = SSP1BUF;
while(!SSP1STATbits.BF);
// Write byte to master
if(count == 255) count = 0; else count++;
SSP1BUF = count;
while(!SSPSTATbits.BF);
}
}
Arduino IDE 1.8.1
#include <SPI.h>
void setup()
{
Serial.begin(9600);
SPI.begin() ;
SPI.setBitOrder(MSBFIRST) ;
SPI.setDataMode(SPI_MODE1) ;
delay(1500) ;
}
void loop()
{
char msg[100];
byte i, n;
for (i = 0 ; i < 10 ; i++) {
n = SPI.transfer(i) ;
sprintf(msg, "%d/%d,", n, i);
Serial.print(msg);
}
Serial.print("\n");
}
我的理想是Arduino接收0-255的值(我忽略了SPI的频率,因为它是一个编程测试)。但是 SPI.transfer() returns 的值为 i(0-9).
网上关于那些IC的技术资料太少了,我很苦恼到底该修哪里。有人知道好方法吗?
我查看了 PIC 16F1826 数据表以检查您的连接。
用于从 SPI1 传输数据的引脚,名为 SDO1,可以是 RA6 或 RB2(来自数据表,第 12 页 [Table 1-2])。
鉴于您将 0 写入 SDO1SEL(复位时它已经为 0),SDO1 似乎在 RB2 上。事实上,你连接的是 RB2 而不是 RA6。
但是您没有清除相应的 TRISB 位以使 RB2 成为输出,如第 236 页(第 25.2.2 章)所述。您当前的程序无法从 RB2/SDO1.
传输数据也许还有其他错误,可能是在设置寄存器时。我建议仔细阅读数据表并修改 PIC 端的所有设置。然后,如果您还有问题,请更新您的问题,我会更新我的答案(发表评论唤醒我)。例如,我没有检查你从 RB2 连接到 Arduino 的正确位置(我看到它连接到引脚 11,但我没有检查它是否正确:像一些编译器一样,我在第一个错误处停止) .
我固定接线(MISO 到 MISO,MOSI 到 MOSI,连接 SS)。
然后我改了PIC16F1上的程序。它附加初始化 RB 引脚和信号接收作为中断。
unsigned char count = 0;
void interrupt OnInterSpi()
{
if (SSP1IF == HIGH){
SSP1IF = LOW;
unsigned char read_data = SSP1BUF;
if(count == 255) count = 0; else count++;
SSP1BUF = count;
}
}
void main(void)
{
OSCCON = 0b00110100;
ANSELA = 0b00000000;
TRISA = 0b00000001;
PORTA = 0b00000000;
ANSELB = 0b00000000;
TRISB = 0b00010010;
PORTB = 0b00000000;
SDO1SEL = 0;
SSP1CON1 = 0b00100100;
SSP1STAT = 0b01000000;
SSP1IF = 0;
SSP1IE = 1;
PEIE = 1;
GIE = 1;
while(1) ;
}
在 Arduino 上,我启用了 SS 信号。
#include <SPI.h>
#define SS_PIN 10
void setup()
{
Serial.begin(9600);
pinMode(SS_PIN, OUTPUT);
digitalWrite(SS_PIN, HIGH);
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
}
char msg[100];
byte i, n;
void loop()
{
digitalWrite(SS_PIN, LOW);
n = SPI.transfer(i);
digitalWrite(SS_PIN, HIGH);
sprintf(msg, "%d/%d, ", n, i);
Serial.print(msg);
}
至少在我的环境中,在 Arduino 的串行监视器上接收到的值正确增加。