|
void _93C46_WriteEnable(void) { // 開始 while ((SPI1->SR & SPI_SR_TXE) == 0); GPIOA->BRR = GPIO_BRR_BR3; // CS=0 GPIOA->BSRR = GPIO_BSRR_BS3; // CS=1 // 發送操作碼及地址碼(=0x30)前5位 SPI1->DR = 0x98; while ((SPI1->SR & SPI_SR_TXE) == 0); // 發送地址碼末位 SPI1->DR = 0x00; while ((SPI1->SR & SPI_SR_TXE) == 0); // 結束 GPIOA->BRR = GPIO_BRR_BR3; // CS=0 delay(); }
void _93C46_Write(void) { // 開始 while ((SPI1->SR & SPI_SR_TXE) == 0); GPIOA->BRR = GPIO_BRR_BR3; // CS=0 GPIOA->BSRR = GPIO_BSRR_BS3; // CS=1 // 發送操作碼及地址碼前5位 SPI1->DR = 0xa0; while ((SPI1->SR & SPI_SR_TXE) == 0); // 發送地址碼末位和前7位數據 SPI1->DR = 0x1e; while ((SPI1->SR & SPI_SR_TXE) == 0); // 發送中間8位數據 SPI1->DR = 0x10; while ((SPI1->SR & SPI_SR_TXE) == 0); // 發送最後一位數據 SPI1->DR = 0x00; while ((SPI1->SR & SPI_SR_TXE) == 0); // 結束 GPIOA->BRR = GPIO_BRR_BR3; // CS=0 delay(); }
int main(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_SPI1EN; // CS(1)接PA3, SCK=PA5接SK(2), MISO=PA6接DO(4), MOSI=PA7接DI(3), ORG懸空選16位模式 // 根據參考手冊RM0008_166頁的Table25,NSS、SCK、MOSI應配置為復用推挽輸出(b),而MISO應配置為帶上拉輸入(8) GPIOA->CRL = 0xb8bb3000; GPIOA->BSRR = GPIO_BSRR_BS6; // 帶上拉輸入 // 數碼管動態掃描端口PB7~PB9 GPIOB->CRH = 0x00000033; GPIOB->CRL = 0x30000000; SPI1->CR1 |= SPI_CR1_MSTR; // 設為主模式 SPI1->CR1 &= ~SPI_CR1_DFF; // 位數為8位 SPI1->CR1 |= SPI_CR1_BR; // BR=111, 選256分頻 SPI1->CR2 |= SPI_CR2_SSOE; // 啟用NSS端口 SPI1->CR1 |= SPI_CR1_SPE; // 啟用SPI _93C46_WriteEnable(); _93C46_Write(); num = _93C46_Read(0); while (1) seg_scan(); }
其中_93C46_Write函數成功地在0號地址寫入了15392這個數! 發送的數據是0xa0, 0x1e, 0x10, 0x00
|
|
寫操作的操作碼為101,地址前5位為00000,合起來10100000=0xa0就是第一個要發送的數據 地址碼末位為0,data=15392=0011110000100000,前7位為0011110,合起來剛好是00011110=0x1e,這是第二個要發送的數據 data的中間8位是00010000=0x10,這是第三個要發送的數據 末位為0,再添上7個無效的0,合起來就是第四個要發送的數據:0x00
|
|
以下程序以及可以讀寫地址[0], [1]處的內容了,但只能讀不能寫[20]處的內容。
#include <stm32f10x.h>
#define _BV(n) (1 << (n))
uint16_t num = 0; const uint8_t seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};
void delay(void) { uint16_t i; for (i = 0; i < 20000; i++); }
void ser_in(uint8_t data) { uint8_t i; for (i = 0; i < 8; i++) { GPIOB->BRR = GPIO_BRR_BR9; // SCLK=>PB9 if (data & 0x80) GPIOB->BSRR = GPIO_BSRR_BS7; // DIO=>PB7 else GPIOB->BRR = GPIO_BRR_BR7; data <<= 1; GPIOB->BSRR = GPIO_BSRR_BS9; } }
void par_out(void) { GPIOB->BRR = GPIO_BRR_BR8; // RCLK=>PB8 GPIOB->BSRR = GPIO_BSRR_BS8; }
void seg_scan(void) { uint8_t i; uint32_t n = num; for (i = 0; i <= 4; i++) { ser_in(seg8[n % 10]); ser_in(_BV(i)); par_out(); delay(); n /= 10; } }
uint16_t _93C46_Read(uint8_t addr) { // 開始 uint16_t data = 0; uint16_t temp; while ((SPI1->SR & SPI_SR_TXE) == 0); GPIOA->BRR = GPIO_BRR_BR3; // CS=0 GPIOA->BSRR = GPIO_BSRR_BS3; // CS=1 // 發送操作碼及地址碼前5位 SPI1->DR = 0xc0 + ((data >> 1) & 0x1f); while ((SPI1->SR & SPI_SR_TXE) == 0); while ((SPI1->SR & SPI_SR_RXNE) == 0); // 等待接收數據 temp = SPI1->DR; // 忽略這次讀取的數據 // 發送地址碼末位,並接收前6位數據 SPI1->DR = (addr << 7) & 0x80; while ((SPI1->SR & SPI_SR_TXE) == 0); while ((SPI1->SR & SPI_SR_RXNE) == 0); temp = SPI1->DR; data = (temp & 0x3f) << 10; // 發送0x00(目的是為了產生接收數據所需的時鐘), 接收中間8位數據 SPI1->DR = 0x00; while ((SPI1->SR & SPI_SR_TXE) == 0); while ((SPI1->SR & SPI_SR_RXNE) == 0); temp = SPI1->DR; data |= temp << 2; // 發送0x00, 接收最後兩位數據 SPI1->DR = 0x00; while ((SPI1->SR & SPI_SR_TXE) == 0); while ((SPI1->SR & SPI_SR_RXNE) == 0); temp = SPI1->DR; data |= temp >> 6; // 結束 GPIOA->BRR = GPIO_BRR_BR3; // CS=0 delay(); return data; }
void _93C46_WriteEnable(uint8_t enabled) { // 開始 while ((SPI1->SR & SPI_SR_TXE) == 0); GPIOA->BRR = GPIO_BRR_BR3; // CS=0 GPIOA->BSRR = GPIO_BSRR_BS3; // CS=1 // 發送操作碼(100)及地址碼(=0x30)或(=0x00) SPI1->DR = (enabled) ? 0x98 : 0x80; while ((SPI1->SR & SPI_SR_TXE) == 0); SPI1->DR = 0x00; while ((SPI1->SR & SPI_SR_TXE) == 0); // 結束 GPIOA->BRR = GPIO_BRR_BR3; // CS=0 delay(); }
void _93C46_Write(uint8_t addr, uint16_t data) { // 開始 while ((SPI1->SR & SPI_SR_TXE) == 0); GPIOA->BRR = GPIO_BRR_BR3; // CS=0 GPIOA->BSRR = GPIO_BSRR_BS3; // CS=1 // 發送操作碼(101)、地址碼以及前7位數據 SPI1->DR = (0xa0 | (addr >> 1)) & 0xff; while ((SPI1->SR & SPI_SR_TXE) == 0); SPI1->DR = ((addr << 7) | (data >> 9)) & 0xff; while ((SPI1->SR & SPI_SR_TXE) == 0); // 發送後9位數據 SPI1->DR = (data >> 1) & 0xff; while ((SPI1->SR & SPI_SR_TXE) == 0); SPI1->DR = (data << 7) & 0x80; while ((SPI1->SR & SPI_SR_TXE) == 0); // 結束 GPIOA->BRR = GPIO_BRR_BR3; // CS=0 delay(); }
int main(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_SPI1EN; // CS(1)接PA3, SCK=PA5接SK(2), MISO=PA6接DO(4), MOSI=PA7接DI(3), ORG懸空選16位模式 // 根據參考手冊RM0008_166頁的Table25,NSS、SCK、MOSI應配置為復用推挽輸出(b),而MISO應配置為帶上拉輸入(8) GPIOA->CRL = 0xb8bb3000; GPIOA->BSRR = GPIO_BSRR_BS6; // 帶上拉輸入 // 數碼管動態掃描端口PB7~PB9 GPIOB->CRH = 0x00000033; GPIOB->CRL = 0x30000000; SPI1->CR1 |= SPI_CR1_MSTR; // 設為主模式 //SPI1->CR1 |= SPI_CR1_DFF; // 位數為16位 SPI1->CR1 |= SPI_CR1_BR; // BR=111, 選256分頻 SPI1->CR2 |= SPI_CR2_SSOE; // 啟用NSS端口 SPI1->CR1 |= SPI_CR1_SPE; // 啟用SPI num = _93C46_Read(0); _93C46_WriteEnable(1); _93C46_Write(0, num + 1);
while (1) seg_scan(); }
|
|
【終於解決讀的問題了!原來是第一個發送的數據中把addr寫成了data了!】 #include <stm32f10x.h>
#define _BV(n) (1 << (n))
uint8_t id = 0; uint16_t num = 0; const uint8_t seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};
void delay(void) { uint16_t i; for (i = 0; i < 20000; i++); }
void ser_in(uint8_t data) { uint8_t i; for (i = 0; i < 8; i++) { GPIOB->BRR = GPIO_BRR_BR9; // SCLK=>PB9 if (data & 0x80) GPIOB->BSRR = GPIO_BSRR_BS7; // DIO=>PB7 else GPIOB->BRR = GPIO_BRR_BR7; data <<= 1; GPIOB->BSRR = GPIO_BSRR_BS9; } }
void par_out(void) { GPIOB->BRR = GPIO_BRR_BR8; // RCLK=>PB8 GPIOB->BSRR = GPIO_BSRR_BS8; }
void seg_scan(void) { uint8_t i; uint32_t n = num; for (i = 0; i <= 4; i++) { ser_in(seg8[n % 10]); ser_in(_BV(i)); par_out(); delay(); n /= 10; } n = id; for (i = 6; i <= 7; i++) { ser_in(seg8[n % 10]); ser_in(_BV(i)); par_out(); delay(); n /= 10; } }
uint16_t _93C46_Read(uint8_t addr) { // SPI中我們配置的是CPOL=0, 即SCK的空閒狀態為低電平; CPHA=0, 也就是在SCK的上升沿對數據進行採樣 // 這裡會產生一個問題: 根據EEPROM手冊, 發送數據倒是沒有問題, 但接收數據時, SCK上升沿後需要等待tPD0=tPD1後數據才會出現 // 如果上升沿出現時就抓取數據, 那麼讀到的不是本位的數據,而是上一位的數據 // 因此,我們接收到的數據都是右移了一位之後的數據 uint16_t data = 0; uint16_t temp; // 開始 GPIOA->BRR = GPIO_BRR_BR3; // CS=0 GPIOA->BSRR = GPIO_BSRR_BS3; // CS=1 SPI1->CR1 |= SPI_CR1_SPE; // 啟用SPI SPI1->DR = 0xc0 + ((addr >> 1) & 0x1f); // 發送操作碼及地址碼前5位 (1) while ((SPI1->SR & SPI_SR_TXE) == 0); // 注意: TXE=1並不代表當前位元組發送完畢, 有可能只發送了一兩個位元組 SPI1->DR = (addr << 7) & 0x80; // 送入下次要發送的內容: 地址碼末位 (2) while ((SPI1->SR & SPI_SR_RXNE) == 0); // 等待接收數據 temp = SPI1->DR; // 忽略這次讀取的數據, 因為收到的數據恆為0xff // 數據的發送和接收是同時進行的 // 只有當前位元組發送完畢了, RXNE才置位, 而TXE早就置位了(參閱手冊上的Figure 240) // RXNE置位表明(1)已發送完畢, 開始發送(2) while ((SPI1->SR & SPI_SR_TXE) == 0); // TXE置位後才能放入新數據, 此時(2)還未發送完畢 SPI1->DR = 0x00; // 送入下次要發的內容: 根據器件手冊上的時序圖, 地址發送完畢後應發送0x00, 即DI一直為低電平,不是什麼都不發 (3) while ((SPI1->SR & SPI_SR_RXNE) == 0); // 等待(2)發送完畢 temp = SPI1->DR; // 收到的數據: 最高位為1(從器件發送的高阻態被視為1), 次高位為0(dummy bit, 空白位), 低6位為所讀取數據的第15~10位 data = (temp & 0x3f) << 10; // 去掉高兩位後送入data變量 while ((SPI1->SR & SPI_SR_TXE) == 0); SPI1->DR = 0x00; // 送入最後一次要發送的內容 (4) while ((SPI1->SR & SPI_SR_RXNE) == 0); // 等待(3)發送完畢 temp = SPI1->DR; // 第9~2位數據 data |= temp << 2; while ((SPI1->SR & SPI_SR_TXE) == 0); while ((SPI1->SR & SPI_SR_RXNE) == 0); // 等待(4)發送完畢 temp = SPI1->DR; data |= temp >> 6; // 結束 GPIOA->BRR = GPIO_BRR_BR3; // CS=0 while (SPI1->SR & SPI_SR_BSY); SPI1->CR1 &= ~SPI_CR1_SPE; // 關閉SPI delay(); return data; }
int main(void) { uint8_t i; RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_SPI1EN; // CS(1)接PA3, SCK=PA5接SK(2), MISO=PA6接DO(4), MOSI=PA7接DI(3), ORG懸空選16位模式 // 根據參考手冊RM0008_166頁的Table25,NSS、SCK、MOSI應配置為復用推挽輸出(b),而MISO應配置為帶上拉輸入(8) GPIOA->CRL = 0xb8bb3000; GPIOA->BSRR = GPIO_BSRR_BS6; // 帶上拉輸入 // 數碼管動態掃描端口PB7~PB9 GPIOB->CRH = 0x00000033; GPIOB->CRL = 0x30000000; SPI1->CR1 |= SPI_CR1_MSTR; // 設為主模式 //SPI1->CR1 |= SPI_CR1_DFF; // 位數為16位 SPI1->CR1 |= SPI_CR1_BR; // BR=111, 選256分頻 SPI1->CR2 |= SPI_CR2_SSOE; // 啟用NSS端口 while (1) { num = _93C46_Read(id); for (i = 0; i < 50; i++) seg_scan(); id++; if (id > 63) id = 0; } }
|
|
之前寫的是: // 發送操作碼及地址碼前5位 SPI1->DR = 0xc0 + ((data >> 1) & 0x1f); 而data的值恆為0,太粗心了!
|