MLX90614传感器是一种非接触式传感器,通过接收和转换红外辐射来读取物体的温度。它可以在三种模式下工作:恒温器,PWM输出和SMBus。在恒温模式下,传感器不需要控制器,只需通过控制开漏负载驱动器将温度保持在指定的范围内即可。在PWM模式下,PWM信号出现在传感器输出上,其占空比取决于温度。为了连接到控制器,最有趣的模式是SMBus。由于此协议与I2C电气和信号兼容,因此我们将使用硬件I2C与传感器配合使用。他将在本文中讨论。通过写入特定的EEPROM单元来配置所有传感器模式。默认情况下,传感器处于SMBus模式。
外观及连接图
. " " STM32F103C8T6 , . 2 I2C. . PB6 - SCL, PB7 - SDA. , 4.7 .
, : mlx90614.h mlx90614.c . LCD A2004 . .
.
#ifndef I2C_DEVICES_I2C_H_
#define I2C_DEVICES_I2C_H_
#include "stm32f1xx.h"
#include <stdio.h>
#include "delay.h"
#define F_APB1 36 // APB1
#define TPCLK1 ( 1000/F_APB1 ) // APB1 ns. ~ 28
#define CCR_VALUE ( 10000 /(TPCLK1 * 2 ) ) // CCR 36 ~ 179
#define TRISE_VALUE ( 1000 / TPCLK1)
. stm32f1xx.h. stdio.h , char LCD. delay.h - .
I2C. . , F_APB1, .
, : RAM EEPROM. RAM . , RAM . " ". . , . MLX90614 . , . EEPROM . .
//---------------- RAM addresses --------------------------------------------
#define MLX90614_RAW_IR_1 0x04 //
#define MLX90614_RAW_IR_2 0x05
#define MLX90614_TA 0x06 //
#define MLX90614_TOBJ_1 0x07 //
#define MLX90614_TOBJ_2 0x08 //
//--------------- EEPROM addresses ------------------------------------------
#define MLX90614_TO_MAX 0x00
#define MLX90614_TO_MIN 0x01
#define MLX90614_PWM_CTRL 0x02
#define MLX90614_TA_RANGE 0x03
#define MLX90614_EMISSIVITY 0x04
#define MLX90614_CONFIG_REGISTER_1 0x05
#define MLX90614_SMBUS_ADDRESS 0x0E // LSByte only
#define MLX90614_ID_NUMBER_1 0x1C
#define MLX90614_ID_NUMBER_2 0x1D
#define MLX90614_ID_NUMBER_3 0x1E
#define MLX90614_ID_NUMBER_4 0x1F
, .
//--------------- Commands ------------------------------------------------
#define MLX90614_RAM_ACCESS 0 // RAM
#define MLX90614_EEPROM_ACCESS 0x20 // EEPROM
#define MLX90614_READ_FLAGS 0xF0 //
#define MLX90614_ENTER_SLEEP_MODE 0xFF //
#define MLX90614_READ 1 //
#define MLX90614_WRITE 0 //
. , . , I2C , - 5A. , , . .
:
void mlx90614Init( void );
double getTemp_Mlx90614_Double( uint16_t address, uint8_t ram_address );
void getTemp_Mlx90614_CharArray( uint16_t address, uint8_t ram_address, char* buf );
uint16_t getAddrFromEEPROM( uint16_t address );
int setAddrToEEPROM ( uint16_t address, uint16_t new_address );
uint16_t readEEPROM( uint16_t address, uint16_t eeprom_address );
void writeEEPROM ( uint16_t address, uint16_t eeprom_address, uint16_t data );
#endif /* I2C_DEVICES_I2C_H_ */
void mlx90614Init( void ) | I2C |
double getTempMlx90614Double( uint16t address, uint8t ram_address ) | double . , . RAM . RAM , 1 2. |
void getTempMlx90614CharArray( uint16t address, uint8t ram_address, char* buf ) | , , char , . LCD |
uint16t getAddrFromEEPROM( uint16t address ) | , EEPROM. . |
int setAddrToEEPROM ( uint16t address, uint16t new_address ) | EEPROM. . |
uint16t readEEPROM( uint16t address, uint16t eepromaddress ) | EEPROM |
void writeEEPROM ( uint16t address, uint16t eepromaddress, uint16t data ) | EEPROM |
. .
void mlx90614Init(void){
delay_ms(120); //
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; //
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // i2c1
GPIOB->CRL |= GPIO_CRL_MODE6 | GPIO_CRL_MODE7; // 50
GPIOB->CRL |= GPIO_CRL_CNF6 | GPIO_CRL_CNF7; // -
I2C1->CR2 &= ~I2C_CR2_FREQ; // APB1
I2C1->CR2 |= F_APB1; // APB1 I2C
I2C1->CR1 &= ~I2C_CR1_PE; // I2C CCR
I2C1->CCR &= ~I2C_CCR_CCR;
I2C1->CCR |= CCR_VALUE;
I2C1->TRISE |= TRISE_VALUE;
I2C1->CR1 |= I2C_CR1_ENPEC; // PEC
I2C1->CR1 |= I2C_CR1_PE; // I2C
I2C1->CR1 |= I2C_CR1_ACK; // ACK
}
. F_APB1, CCR_VALUE TRISE_VALUE , . I2C CCR ( ) ACK I2C , ACK .
double getTemp_Mlx90614_Double( uint16_t address,
uint8_t ram_address){
uint16_t temp ; //
uint8_t temp_lsb ; //
double temp_result ; //
double temp_double ; // , double
address = address<<1; // (
// 1- /)
I2C1->CR1 |= I2C_CR1_START;
while (!(I2C1->SR1 & I2C_SR1_SB)){}
(void) I2C1->SR1;
I2C1->DR = address | MLX90614_WRITE; // , MLX90614
while (!(I2C1->SR1 & I2C_SR1_ADDR)){}
(void) I2C1->SR1;
(void) I2C1->SR2;
I2C1->DR= ram_address; // RAM MLX90614
while (!(I2C1->SR1 & I2C_SR1_TXE)){}
I2C1->CR1 |= I2C_CR1_START; //
while (!(I2C1->SR1 & I2C_SR1_SB)){}
(void) I2C1->SR1;
I2C1->DR = address | MLX90614_READ; //
while (!(I2C1->SR1 & I2C_SR1_ADDR)){}
(void) I2C1->SR1;
(void) I2C1->SR2;
while(!(I2C1->SR1 & I2C_SR1_RXNE)){}
temp_lsb = I2C1->DR; //
while(!(I2C1->SR1 & I2C_SR1_RXNE)){}
temp = I2C1->DR; //
I2C1->CR1 |= I2C_CR1_STOP;
temp = (temp & 0x007F) << 8; // ,
temp |= temp_lsb;
temp_double = (double) temp; // double
temp_result = ((temp_double * 0.02)- 0.01 ); //
temp_result = temp_result - 273.15; // .
return temp_result;
}
, 1 , 1 , 0 - . I2C. 5A, B4 B5 . , , . . . , - (temp & 0x007F).
, LCD, . void getTempMlx90614CharArray, char , sprintf(), stdio.h
void getTemp_Mlx90614_CharArray( uint16_t address, uint8_t ram_address, char* buf){
double t;
t = getTemp_Mlx90614_Double(address,ram_address);
sprintf(buf, "%.1f",t);
return ;
}
RAM :
START
, 1 (). - 0
RAM RAM. RAM .
START
1 .
STOP
. , . EEPROM .
EEPROM :
START
, 1 (). - 0
EEPROM EEPROM ( )
START
STOP
EEPROM
uint16_t readEEPROM( uint16_t address, uint16_t eeprom_address ){
uint16_t data_msb;
uint16_t data_lsb;
uint16_t data_result;
address = address<<1; // ( + 1 /)
I2C1->CR1 |= I2C_CR1_START;
while (!(I2C1->SR1 & I2C_SR1_SB)){}
(void) I2C1->SR1;
I2C1->DR = address | MLX90614_WRITE; // , MLX90614
while (!(I2C1->SR1 & I2C_SR1_ADDR)){}
(void) I2C1->SR1;
(void) I2C1->SR2;
I2C1->DR= eeprom_address | MLX90614_EEPROM_ACCESS; // EEPROM MLX90614
while (!(I2C1->SR1 & I2C_SR1_TXE)){}
I2C1->CR1 |= I2C_CR1_START; //
while (!(I2C1->SR1 & I2C_SR1_SB)){}
(void) I2C1->SR1;
I2C1->DR = address | MLX90614_READ; //
while (!(I2C1->SR1 & I2C_SR1_ADDR)){}
(void) I2C1->SR1;
(void) I2C1->SR2;
//I2C1->CR1 &= ~I2C_CR1_ACK;
while (!(I2C1->SR1 & I2C_SR1_RXNE)){};
data_lsb = I2C1->DR; //
while(!(I2C1->SR1 & I2C_SR1_RXNE)){}
data_msb = I2C1->DR; //
I2C1->CR1 |= I2C_CR1_STOP;
data_result = ((data_msb << 8) | data_lsb) ;
return data_result;
}
EEPROM RAM. .
. :
START
,
EEPROM EEPROM
PEC ( )
STOP
, . , , .
EEPROM
void writeEEPROM ( uint16_t address, uint16_t eeprom_address, uint16_t data ){
address = address<<1; // (.. + 1 /)
I2C1->CR1 |= I2C_CR1_START;
while (!(I2C1->SR1 & I2C_SR1_SB)){}
(void) I2C1->SR1;
I2C1->DR = address | MLX90614_WRITE; // , MLX90614
while (!(I2C1->SR1 & I2C_SR1_ADDR)){}
(void) I2C1->SR1;
(void) I2C1->SR2;
I2C1->DR= eeprom_address | MLX90614_EEPROM_ACCESS; // EEPROM MLX90614
while (!(I2C1->SR1 & I2C_SR1_TXE)){}
I2C1->DR = ( uint8_t ) ( data & 0x00FF ); //
while(!(I2C1->SR1 & I2C_SR1_BTF)){}
I2C1->DR = ( uint8_t ) ( data >> 8 ) ; //
while(!(I2C1->SR1 & I2C_SR1_BTF)){}
I2C1->CR1 |= I2C_CR1_PEC; // PEC
I2C1->CR1 |= I2C_CR1_STOP;
return ;
}
EEPROM. . , .
uint16_t getAddrFromEEPROM ( uint16_t address ){
uint16_t addr_eeprom;
addr_eeprom = readEEPROM( address, MLX90614_SMBUS_ADDRESS );
return addr_eeprom;
}
. , readEEPROM() EEPROM .
EEPROM . MLX90614 EEPROM:
,
10
10
, ,
. . , , , . - , EEPROM ? ? , . , .
EEPROM
int setAddrToEEPROM ( uint16_t address, uint16_t new_address ){
uint16_t addr;
writeEEPROM ( address, MLX90614_SMBUS_ADDRESS, 0x0); //
delay_ms(10);
writeEEPROM (address, MLX90614_SMBUS_ADDRESS, new_address ); //
delay_ms(10);
addr = readEEPROM ( address, MLX90614_SMBUS_ADDRESS ); //
if ( addr == new_address){
return 1;
}
else return 0;
}
. main()
#include "main.h"
#include <stdio.h>
int main (void){
clk_ini(); //
lcd_2004a_init(); // a2004
mlx90614Init(); // I2C
uint16_t geted_eeprom_address;
char char_eeprom_address[20];
char crystal_temp[10]; //
char first_sensor_temp[10];
// EEPROM LCD
geted_eeprom_address = getAddrFromEEPROM( 0x5A );
sprintf(char_eeprom_address, "%x", (uint8_t) geted_eeprom_address);
sendStr("addr value:", 3, 0);
sendStr (char_eeprom_address, 3, 14 );
setAddrToEEPROM (0x5A , 0xA); //
// LCD
geted_eeprom_address = getAddrFromEEPROM( 0x5A );
sprintf(char_eeprom_address, "%x", (uint8_t) geted_eeprom_address);
sendStr("new addr :", 4, 0);
sendStr (char_eeprom_address, 4, 14 );
while(1){
//
getTemp_Mlx90614_CharArray ( 0x5A, MLX90614_TA, crystal_temp );
sendStr( "Crystal Temp :", 1, 0 );
sendStr( crystal_temp, 1, 14 );
delay_s(1);
getTemp_Mlx90614_CharArray ( 0x5A, MLX90614_TOBJ_1, first_sensor_temp );
sendStr( "Sensor Temp :", 2, 0 );
sendStr( first_sensor_temp, 2, 14 );
delay_s(1);
}
}
main.h
#ifndef CORE_INC_MAIN_H_
#define CORE_INC_MAIN_H_
#include "stm32f1xx.h"
#include "clk_ini.h" //
#include "delay.h" //
#include "lcd_20x4.h" // LCD A2004
#include "mlx90614.h" //
#endif /* CORE_INC_MAIN_H_ */
:
总之,完整的项目清单
mlx90614.h
#ifndef I2C_DEVICES_I2C_H_
#define I2C_DEVICES_I2C_H_
#include "stm32f1xx.h"
#include <stdio.h>
#include "delay.h"
#define F_APB1 36 // APB1
#define TPCLK1 ( 1000/F_APB1 ) // APB1 ns. ~ 28
#define CCR_VALUE ( 10000 /(TPCLK1 * 2 ) ) // CCR 36 ~ 179
#define TRISE_VALUE ( 1000 / TPCLK1)
//---------------- RAM addresses --------------------------------------------
#define MLX90614_RAW_IR_1 0x04 //
#define MLX90614_RAW_IR_2 0x05
#define MLX90614_TA 0x06 //
#define MLX90614_TOBJ_1 0x07 //
#define MLX90614_TOBJ_2 0x08 //
//--------------- EEPROM addresses ------------------------------------------
#define MLX90614_TO_MAX 0x00
#define MLX90614_TO_MIN 0x01
#define MLX90614_PWM_CTRL 0x02
#define MLX90614_TA_RANGE 0x03
#define MLX90614_EMISSIVITY 0x04
#define MLX90614_CONFIG_REGISTER_1 0x05
#define MLX90614_SMBUS_ADDRESS 0x0E // LSByte only
#define MLX90614_ID_NUMBER_1 0x1C
#define MLX90614_ID_NUMBER_2 0x1D
#define MLX90614_ID_NUMBER_3 0x1E
#define MLX90614_ID_NUMBER_4 0x1F
//--------------- Commands ------------------------------------------------
#define MLX90614_RAM_ACCESS 0 // RAM
#define MLX90614_EEPROM_ACCESS 0x20 // EEPROM
#define MLX90614_READ_FLAGS 0xF0 //
#define MLX90614_ENTER_SLEEP_MODE 0xFF //
#define MLX90614_READ 1 //
#define MLX90614_WRITE 0 //
void mlx90614Init( void );
double getTemp_Mlx90614_Double( uint16_t address, uint8_t ram_address );
void getTemp_Mlx90614_CharArray( uint16_t address, uint8_t ram_address, char* buf );
uint16_t getAddrFromEEPROM( uint16_t address );
int setAddrToEEPROM ( uint16_t address, uint16_t new_address );
uint16_t readEEPROM( uint16_t address, uint16_t eeprom_address );
void writeEEPROM ( uint16_t address, uint16_t eeprom_address, uint16_t data );
#endif /* I2C_DEVICES_I2C_H_ */
mlx90614.c
#include "mlx90614.h"
/********************************************************************************************
* I2C MLX90614 *
* *
********************************************************************************************/
void mlx90614Init(void){
delay_ms(120); //
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; //
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // i2c1
GPIOB->CRL |= GPIO_CRL_MODE6 | GPIO_CRL_MODE7; // 50
GPIOB->CRL |= GPIO_CRL_CNF6 | GPIO_CRL_CNF7; // -
I2C1->CR2 &= ~I2C_CR2_FREQ; // APB1
I2C1->CR2 |= F_APB1; // APB1 I2C
I2C1->CR1 &= ~I2C_CR1_PE; // I2C CCR
I2C1->CCR &= ~I2C_CCR_CCR;
I2C1->CCR |= CCR_VALUE;
I2C1->TRISE |= TRISE_VALUE;
I2C1->CR1 |= I2C_CR1_ENPEC; // PEC
I2C1->CR1 |= I2C_CR1_PE; // I2C
I2C1->CR1 |= I2C_CR1_ACK; // ACK
}
/********************************************************************************************
* . double. *
* *
* : *
* address - MLX90614 *
* *
* ram_address RAM- ( . .h ) : *
* *
* MLX90614_TA - *
* MLX90614_TOBJ_1 - *
* MLX90614_TOBJ_2 - *
*******************************************************************************************/
double getTemp_Mlx90614_Double( uint16_t address,
uint8_t ram_address){
uint16_t temp ; //
uint8_t temp_lsb ; //
double temp_result ; //
double temp_double ; // , double
address = address<<1; // (
// 1- /)
I2C1->CR1 |= I2C_CR1_START;
while (!(I2C1->SR1 & I2C_SR1_SB)){}
(void) I2C1->SR1;
I2C1->DR = address | MLX90614_WRITE; // , MLX90614
while (!(I2C1->SR1 & I2C_SR1_ADDR)){}
(void) I2C1->SR1;
(void) I2C1->SR2;
I2C1->DR= ram_address; // RAM MLX90614
while (!(I2C1->SR1 & I2C_SR1_TXE)){}
I2C1->CR1 |= I2C_CR1_START; //
while (!(I2C1->SR1 & I2C_SR1_SB)){}
(void) I2C1->SR1;
I2C1->DR = address | MLX90614_READ; //
while (!(I2C1->SR1 & I2C_SR1_ADDR)){}
(void) I2C1->SR1;
(void) I2C1->SR2;
while(!(I2C1->SR1 & I2C_SR1_RXNE)){}
temp_lsb = I2C1->DR; //
while(!(I2C1->SR1 & I2C_SR1_RXNE)){}
temp = I2C1->DR; //
I2C1->CR1 |= I2C_CR1_STOP;
temp = (temp & 0x007F) << 8; // ,
temp |= temp_lsb;
temp_double = (double) temp; // double
temp_result = ((temp_double * 0.02)- 0.01 ); //
temp_result = temp_result - 273.15; // .
return temp_result;
}
/********************************************************************************************
* , , char . *
* *
* : *
* address - MLX90614 *
* *
* ram_address RAM- ( . .h ) : *
* *
* MLX90614_TA - *
* MLX90614_TOBJ_1 - *
* MLX90614_TOBJ_2 - *
* *
* *buf - *
*******************************************************************************************/
void getTemp_Mlx90614_CharArray( uint16_t address, uint8_t ram_address, char* buf){
double t;
t = getTemp_Mlx90614_Double(address,ram_address);
sprintf(buf, "%.1f",t);
return ;
}
/********************************************************************************************
* EEPROM *
* : *
* address - *
* eeprom_address - EEPROM *
* *
* : *
* EEPROM uint16_t *
* *
* ******************************************************************************************/
uint16_t readEEPROM( uint16_t address, uint16_t eeprom_address ){
uint16_t data_msb;
uint16_t data_lsb;
uint16_t data_result;
address = address<<1; // ( + 1 /)
I2C1->CR1 |= I2C_CR1_START;
while (!(I2C1->SR1 & I2C_SR1_SB)){}
(void) I2C1->SR1;
I2C1->DR = address | MLX90614_WRITE; // , MLX90614
while (!(I2C1->SR1 & I2C_SR1_ADDR)){}
(void) I2C1->SR1;
(void) I2C1->SR2;
I2C1->DR= eeprom_address | MLX90614_EEPROM_ACCESS; // EEPROM MLX90614
while (!(I2C1->SR1 & I2C_SR1_TXE)){}
I2C1->CR1 |= I2C_CR1_START; //
while (!(I2C1->SR1 & I2C_SR1_SB)){}
(void) I2C1->SR1;
I2C1->DR = address | MLX90614_READ; //
while (!(I2C1->SR1 & I2C_SR1_ADDR)){}
(void) I2C1->SR1;
(void) I2C1->SR2;
//I2C1->CR1 &= ~I2C_CR1_ACK;
while (!(I2C1->SR1 & I2C_SR1_RXNE)){};
data_lsb = I2C1->DR; //
while(!(I2C1->SR1 & I2C_SR1_RXNE)){}
data_msb = I2C1->DR; //
I2C1->CR1 |= I2C_CR1_STOP;
data_result = ((data_msb << 8) | data_lsb) ;//& 0x1F;
return data_result;
}
/********************************************************************************************
* EEPROM *
* *
* : *
* address - *
* eeprom_address - EEPROM *
* data - *
********************************************************************************************/
void writeEEPROM ( uint16_t address, uint16_t eeprom_address, uint16_t data ){
address = address<<1; // (.. + 1 /)
I2C1->CR1 |= I2C_CR1_START;
while (!(I2C1->SR1 & I2C_SR1_SB)){}
(void) I2C1->SR1;
I2C1->DR = address | MLX90614_WRITE; // , MLX90614
while (!(I2C1->SR1 & I2C_SR1_ADDR)){}
(void) I2C1->SR1;
(void) I2C1->SR2;
I2C1->DR= eeprom_address | MLX90614_EEPROM_ACCESS; // EEPROM MLX90614
while (!(I2C1->SR1 & I2C_SR1_TXE)){}
I2C1->DR = ( uint8_t ) ( data & 0x00FF ); //
while(!(I2C1->SR1 & I2C_SR1_BTF)){}
I2C1->DR = ( uint8_t ) ( data >> 8 ) ; //
while(!(I2C1->SR1 & I2C_SR1_BTF)){}
I2C1->CR1 |= I2C_CR1_PEC; // PEC
I2C1->CR1 |= I2C_CR1_STOP;
return ;
}
/********************************************************************************************
* EEPROM *
* *
* : *
* address - *
* *
* : *
* uint8_t *
* *
*******************************************************************************************/
uint16_t getAddrFromEEPROM ( uint16_t address ){
uint16_t addr_eeprom;
addr_eeprom = readEEPROM( address, MLX90614_SMBUS_ADDRESS );
return addr_eeprom;
}
/********************************************************************************************
* EEPROM *
* *
* : *
* address - *
* new_address - *
* *
* 1 - / 0 - *
********************************************************************************************/
int setAddrToEEPROM ( uint16_t address, uint16_t new_address ){
uint16_t addr;
writeEEPROM ( address, MLX90614_SMBUS_ADDRESS, 0x0); //
delay_ms(10);
writeEEPROM (address, MLX90614_SMBUS_ADDRESS, new_address ); //
delay_ms(10);
addr = readEEPROM ( address, MLX90614_SMBUS_ADDRESS ); //
if ( addr == new_address){
return 1;
}
else return 0;
}
clk_ini.h
#ifndef INC_CLK_INI_H_
#define INC_CLK_INI_H_
#include "stm32f1xx.h"
int clk_ini(void);
#endif /* INC_CLK_INI_H_ */
clk_ini.c
#include "clk_ini.h"
int clk_ini(void){
RCC->CR |= (1 << RCC_CR_HSEON_Pos);
__IO int startCounter;
for(startCounter = 0; ; startCounter++){
if(RCC->CR & (1 << RCC_CR_HSERDY_Pos)){
break;
}// if
if(startCounter > 0x1000){
RCC->CR &= ~(1 << RCC_CR_HSEON_Pos);
return 1;
}
}// for
RCC->CFGR |= (0x07 << RCC_CFGR_PLLMULL_Pos) // PLL x9
|(0x01 << RCC_CFGR_PLLSRC_Pos); // start clocking PLL of HSE
RCC->CR |= (1 << RCC_CR_PLLON_Pos);
for(startCounter = 0; ; startCounter++){
if(RCC->CR & (1 << RCC_CR_PLLRDY_Pos)){
break;
}//if
if(startCounter > 0x1000){
RCC->CR &= ~(1 << RCC_CR_HSEON_Pos);
RCC->CR &= ~(1 << RCC_CR_PLLON_Pos);
return 2;
}// if
}// for
////////////////////////////////////////////////////////////
// FLASH
////////////////////////////////////////////////////////////
// 2 Flash
// 48 MHz < SYSCLK <= 72 MHz
FLASH->ACR |= (0x02<<FLASH_ACR_LATENCY_Pos);
//
RCC->CFGR |= (0x00<<RCC_CFGR_PPRE2_Pos) // APB2 1
| (0x04<<RCC_CFGR_PPRE1_Pos) // APB1 2
| (0x00<<RCC_CFGR_HPRE_Pos); // AHB
RCC->CFGR |= (0x02<<RCC_CFGR_SW_Pos); // PLL
//,
while((RCC->CFGR & RCC_CFGR_SWS_Msk) != (0x02<<RCC_CFGR_SWS_Pos))
{
}
// ,
//
// RC-
//
RCC->CR &= ~(1<<RCC_CR_HSION_Pos);
//
//
// PLL .
//
return 0;
}
延迟
#ifndef DELAY_DELAY_H_
#define DELAY_DELAY_H_
#include "stm32f1xx.h"
#define F_CPU 72000000UL
#define US F_CPU/1000000
#define MS F_CPU/1000
#define SYSTICK_MAX_VALUE 16777215
#define US_MAX_VALUE SYSTICK_MAX_VALUE/(US)
#define MS_MAX_VALUE SYSTICK_MAX_VALUE/(MS)
void delay_us(uint32_t us); // 233
void delay_ms(uint32_t ms); // 233
void delay_s(uint32_t s);
延迟
#include "delay.h"
/* */
void delay_us(uint32_t us){ // 233 016
if (us > US_MAX_VALUE || us == 0)
return;
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk; // 0
SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk; //
SysTick->LOAD = (US * us-1); //
SysTick->VAL = 0; // SYST_CVR
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //
while(!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk)); // COUNFLAG SYST_CSR
SysTick->CTRL &= ~SysTick_CTRL_COUNTFLAG_Msk; // COUNTFLAG
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //
return;
}
void delay_ms(uint32_t ms){ // 233
if(ms > MS_MAX_VALUE || ms ==0)
return;
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;
SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk;
SysTick->LOAD = (MS * ms);
SysTick->VAL = 0;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
while(!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk));
SysTick->CTRL &= ~SysTick_CTRL_COUNTFLAG_Msk;
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
return;
}
void delay_s(uint32_t s){
for(int i=0; i<s*5;i++) delay_ms(200);
return;
}
lcd_20x4.h
#ifndef LCD_LCD_20X4_2004A_LCD_20X4_H_
#define LCD_LCD_20X4_2004A_LCD_20X4_H_
#include "stm32f1xx.h"
#include "delay.h"
// display commands
#define CLEAR_DISPLAY 0x1
#define RETURN_HOME 0x2
#define ENTRY_MODE_SET 0x6 // mode cursor shift rihgt, display non shift
#define DISPLAY_ON 0xC // non cursor
#define DISPLAY_OFF 0x8
#define CURSOR_SHIFT_LEFT 0x10
#define CURSOR_SHIFT_RIGHT 0x14
#define DISPLAY_SHIFT_LEFT 0x18
#define DISPLAY_SHIFT_RIGHT 0x1C
#define DATA_BUS_4BIT_PAGE0 0x28
#define DATA_BUS_4BIT_PAGE1 0x2A
#define DATA_BUS_8BIT_PAGE0 0x38
#define SET_CGRAM_ADDRESS 0x40 // usage address |= SET_CGRAM_ADDRESS
#define SET_DDRAM_ADDRESS 0x80
// ODR
#define PIN_RS 0x1
#define PIN_EN 0x2
#define PIN_D4 0x1000
#define PIN_D5 0x2000
#define PIN_D6 0x4000
#define PIN_D7 0x8000
#define LCD_PORT GPIOB
#define LCD_ODR LCD_PORT->ODR
#define LCD_PIN_RS() LCD_PORT->CRL |= GPIO_CRL_MODE0_0;\
LCD_PORT->CRL &= ~GPIO_CRL_CNF0; // PB0 -, 10
#define LCD_PIN_EN() LCD_PORT->CRL |= GPIO_CRL_MODE1_0;\
LCD_PORT->CRL &= ~GPIO_CRL_CNF1; // PB1
#define LCD_PIN_D4() LCD_PORT->CRH |= GPIO_CRH_MODE12_0;\
LCD_PORT->CRH &= ~GPIO_CRH_CNF12; // PB7
#define LCD_PIN_D5() LCD_PORT->CRH |= GPIO_CRH_MODE13_0;\
LCD_PORT->CRH &= ~GPIO_CRH_CNF13; // PB6
#define LCD_PIN_D6() LCD_PORT->CRH |= GPIO_CRH_MODE14_0;\
LCD_PORT->CRH &= ~GPIO_CRH_CNF14; // PB5
#define LCD_PIN_D7() LCD_PORT->CRH |= GPIO_CRH_MODE15_0;\
LCD_PORT->CRH &= ~GPIO_CRH_CNF15; // PB10
#define LCD_PIN_MASK (PIN_RS | PIN_EN | PIN_D7 | PIN_D6 | PIN_D5 | PIN_D4) // 0b0000000011110011
void lcd_2004a_init(void); //
void sendByte(char byte, int isData);
void sendStr(char *str, int row , int position); //
#endif /* LCD_LCD_20X4_2004A_LCD_20X4_H_ */
lcd_20x4.c
#include "lcd_20x4.h"
// LCD
void lcdInit(void); //
void sendByte(char byte, int isData){
//
LCD_ODR &= ~LCD_PIN_MASK;
if(isData == 1) LCD_ODR |= PIN_RS; // RS
else LCD_ODR &= ~(PIN_RS); // RS
// E
LCD_ODR |= PIN_EN;
//
if(byte & 0x80) LCD_ODR |= PIN_D7;
if(byte & 0x40) LCD_ODR |= PIN_D6;
if(byte & 0x20) LCD_ODR |= PIN_D5;
if(byte & 0x10) LCD_ODR |= PIN_D4;
LCD_ODR &= ~PIN_EN; //
// RS
LCD_ODR &= ~(LCD_PIN_MASK & ~PIN_RS);
// E
LCD_ODR |= PIN_EN;
//
if(byte & 0x8) LCD_ODR |= PIN_D7;
if(byte & 0x4) LCD_ODR |= PIN_D6;
if(byte & 0x2) LCD_ODR |= PIN_D5;
if(byte & 0x1) LCD_ODR |= PIN_D4;
//
LCD_ODR &= ~(PIN_EN);
delay_us(40);
return;
}
// 50
void lcd_2004a_init(void){
//---------------------- ----------------------------------------------------
if(LCD_PORT == GPIOB) RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
else if (LCD_PORT == GPIOA) RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
else return;
//--------------------- LCD-----------------------------------------------------
LCD_PIN_RS();
LCD_PIN_EN();
LCD_PIN_D7();
LCD_PIN_D6();
LCD_PIN_D5();
LCD_PIN_D4();
lcdInit();
return ;
}
//--------------------- -----------------------------------------------------------
void lcdInit(void){
delay_ms(200); //
sendByte(0x33, 0); // 0011
delay_us(120);
sendByte(0x32, 0); // 00110010
delay_us(40);
sendByte(DATA_BUS_4BIT_PAGE0, 0); // 4
delay_us(40);
sendByte(DISPLAY_OFF, 0); //
delay_us(40);
sendByte(CLEAR_DISPLAY, 0); //
delay_ms(2);
sendByte(ENTRY_MODE_SET, 0); //
delay_us(40);
sendByte(DISPLAY_ON, 0);//
delay_us(40);
return ;
}
void sendStr( char *str, int row , int position ){
char start_address;
switch (row) {
case 1:
start_address = 0x0; // 1
break;
case 2:
start_address = 0x40; // 2
break;
case 3:
start_address = 0x14; // 3
break;
case 4:
start_address = 0x54; // 4
break;
}
start_address += position; //
sendByte((start_address |= SET_DDRAM_ADDRESS), 0); // DDRAM
delay_ms(4);
while(*str != '\0'){
sendByte(*str, 1);
str++;
}// while
}