溫濕度可以正常讀取了,接下來就是調SPI和OLED顯示,嘗試將數據通過OLED屏顯示出來。
查看OLED屏的資料,支持多種連接方式,默認的是4線SPI,但是沒有MISO,也就是說OLED屏沒有輸出信號,不可讀。那就在Information sheet上找SPI的管腳,老原因接著用用X32接口上的SPI2。為了接線方便些,用鄰近的管腳作RST和DC信號
由于X32上只有一個3.3V,溫濕度傳感器最高耐壓5.5V,就把它接到5V上吧,按如下方式連接OLED屏和溫濕度傳感器
接下來依然是通過MHC來使能SPI驅動
1. 打開MHC的Options選項卡,找到SPI對應的driver選項打開并做相應的配置,我的配置如下
2. 打開MHC的Pin Settings,將RG6、RG7、RG8、RG9設置為SPI管腳,RB8設置為DC,RD7設置為RST
3. 然后生成代碼,主要包含以下幾個源文件
4. 分析SPI驅動代碼后可知在SYS_Initialize中已經根據用戶的配置調用了SPI相關的初始化函數,所以使用時只需要在代碼里直接調用drv_spi_mapping.c中的其他API就可以了。但是SPI的速率較高,我設置的是5M,如果使用中斷模式,處理不好中斷頻繁產生的話,不知道CPU是不是吃得消;以前在SAM4N上用過輪詢方式的SPI,索性將代碼拿來直接用,等到調通了之后再改成中斷甚至DMA看能不能處理好。先不用MHC產生的代碼了,相當于只利用了它的初始化和訪問硬件的PLIB庫。主要的spi和ssd1306的代碼如下
bsp_spi.c
void spi_select_device(PORTS_CHANNEL ch, PORTS_BIT_POS pos)
{
SYS_PORTS_PinClear(PORTS_ID_0, ch, pos);
}
void spi_deselect_device(PORTS_CHANNEL ch, PORTS_BIT_POS pos)
{
SYS_PORTS_PinSet(PORTS_ID_0, ch, pos);
}
static inline void spi_write_single(uint8_t data)
{
PLIB_SPI_BufferWrite(SPI_ID_2, data);
}
bsp_ssd1306.c
#define SSD1306_SPI_INTERFACE
#define SSD1306_SPI SPI
#define SSD1306_DC_PIN_CH PORT_CHANNEL_B
#define SSD1306_DC_PIN_POS PORTS_BIT_POS_8
#define SSD1306_CS_PIN_CH PORT_CHANNEL_G
#define SSD1306_CS_PIN_POS PORTS_BIT_POS_9
#define SSD1306_RES_PIN_CH PORT_CHANNEL_D
#define SSD1306_RES_PIN_POS PORTS_BIT_POS_7
#define UG_2832HSWEG04_BAUDRATE 5000000
#define SSD1306_LATENCY 10
#define ssd1306_reset_clear() SYS_PORTS_PinClear(PORTS_ID_0, SSD1306_RES_PIN_CH, SSD1306_RES_PIN_POS)
#define ssd1306_reset_set() SYS_PORTS_PinSet(PORTS_ID_0, SSD1306_RES_PIN_CH, SSD1306_RES_PIN_POS)
// Data/CMD select, PC21Could not add reference to assembly IronPython.wpf
#define ssd1306_sel_data() SYS_PORTS_PinSet(PORTS_ID_0, SSD1306_DC_PIN_CH, SSD1306_DC_PIN_POS)
#define ssd1306_sel_cmd() SYS_PORTS_PinClear(PORTS_ID_0, SSD1306_DC_PIN_CH, SSD1306_DC_PIN_POS)
static inline void delay_us(unsigned int n)
{
volatile uint32_t i;
volatile uint32_t j;
i = (n > 0) ? n : 1;
for (; i > 0; i--) {
for (j = 0; j < 100; j++) {
;
}
}
}
static inline void ssd1306_write_command(uint8_t command)
{
spi_select_device(SSD1306_CS_PIN_CH, SSD1306_CS_PIN_POS);
ssd1306_sel_cmd();
spi_write_single(command);
delay_us(SSD1306_LATENCY); // At least 3us
spi_deselect_device(SSD1306_CS_PIN_CH, SSD1306_CS_PIN_POS);
}
static inline void ssd1306_write_data(uint8_t data)
{
spi_select_device(SSD1306_CS_PIN_CH, SSD1306_CS_PIN_POS);
ssd1306_sel_data();
spi_write_single(data);
delay_us(SSD1306_LATENCY); // At least 3us
spi_deselect_device(SSD1306_CS_PIN_CH, SSD1306_CS_PIN_POS);
}
static inline void ssd1306_hard_reset(void)
{
ssd1306_reset_clear();
delay_us(SSD1306_LATENCY); // At least 3us
ssd1306_reset_set();
delay_us(SSD1306_LATENCY); // At least 3us
}
static inline void ssd1306_set_page_address(uint8_t address)
{
// Make sure that the address is 4 bits (only 8 pages)
address &= 0x0F;
ssd1306_write_command(SSD1306_CMD_SET_PAGE_START_ADDRESS(address));
}
static inline void ssd1306_set_column_address(uint8_t address)
{
// Make sure the address is 7 bits
address &= 0x7F;
ssd1306_write_command(SSD1306_CMD_SET_HIGH_COL(address >> 4));
ssd1306_write_command(SSD1306_CMD_SET_LOW_COL(address & 0x0F));
}
static inline void ssd1306_clear(void)
{
uint8_t page = 0;
uint8_t col = 0;
for (page = 0; page < 8; ++page)
{
ssd1306_set_page_address(page);
ssd1306_set_column_address(0);
for (col = 0; col < 128; ++col)
{
ssd1306_write_data(0x00);
}
}
}
void ssd1306_init(void)
{
// Do a hard reset of the OLED display controller
ssd1306_hard_reset();
// Initialize the interface
ssd1306_interface_init();
// 1/32 Duty (0x0F~0x3F)
ssd1306_write_command(SSD1306_CMD_SET_MULTIPLEX_RATIO);
ssd1306_write_command(0x3F);
// Shift Mapping RAM Counter (0x00~0x3F)
ssd1306_write_command(SSD1306_CMD_SET_DISPLAY_OFFSET);
ssd1306_write_command(0x00);
// Set Mapping RAM Display Start Line (0x00~0x3F)
ssd1306_write_command(SSD1306_CMD_SET_START_LINE(0x00));
// Set Column Address 0 Mapped to SEG0
ssd1306_write_command(SSD1306_CMD_SET_SEGMENT_RE_MAP_COL127_SEG0);
// Set COM/Row Scan Scan from COM63 to 0
ssd1306_write_command(SSD1306_CMD_SET_COM_OUTPUT_SCAN_DOWN);
// Set COM Pins hardware configuration
ssd1306_write_command(SSD1306_CMD_SET_COM_PINS);
ssd1306_write_command(0x12);
ssd1306_set_contrast(0x8F);
// Disable Entire display On
ssd1306_write_command(SSD1306_CMD_ENTIRE_DISPLAY_AND_GDDRAM_ON);
ssd1306_display_invert_disable();
// Set Display Clock Divide Ratio / Oscillator Frequency (Default => 0x80)
ssd1306_write_command(SSD1306_CMD_SET_DISPLAY_CLOCK_DIVIDE_RATIO);
ssd1306_write_command(0x80);
// Enable charge pump regulator
ssd1306_write_command(SSD1306_CMD_SET_CHARGE_PUMP_SETTING);
ssd1306_write_command(0x14);
// Set VCOMH Deselect Level
ssd1306_write_command(SSD1306_CMD_SET_VCOMH_DESELECT_LEVEL);
ssd1306_write_command(0x40); // Default => 0x20 (0.77*VCC)
// Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
ssd1306_write_command(SSD1306_CMD_SET_PRE_CHARGE_PERIOD);
ssd1306_write_command(0xF1);
ssd1306_display_on();
}
void ssd1306_write_text(const char *string)
{
uint8_t *char_ptr;
uint8_t i;
while (*string != 0) {
if (*string < 0x7F) {
char_ptr = font_table[*string - 32];
for (i = 1; i <= char_ptr[0]; i++) {
ssd1306_write_data(char_ptr[i]);
}
ssd1306_write_data(0x00);
}
string++;
}
}
5. 最后在APP_Tasks中初始化ssd1306,把原先讀溫濕度操作之后的串口打印,改成顯示數據,每秒讀一次并通過OLED屏顯示出來
調試還算順利,OLED顯示如下
雖然顯示的終端由串口改成了OLED屏,但換個馬甲依然無法掩飾它的簡陋。下一步就是移植μGUI裝一回大尾巴狼,哈哈哈
-
PIC32MX470
+關注
關注
0文章
5瀏覽量
1803
發布評論請先 登錄
相關推薦
評論