The MLX90614 sensor is a non-contact sensor that reads the temperature of an object by receiving and converting infrared radiation. It can work in three modes: thermostat, PWM output and SMBus. In thermostat mode, the sensor does not need a controller, it just keeps the temperature within the specified limits by controlling the open drain load driver. In PWM mode, a PWM signal appears at the sensor output, the duty cycle of which depends on the temperature. In order to connect to the controller, the most interesting mode is SMBus. Since this protocol is electrically and signalally compatible with I2C, we will work with the sensor using hardware I2C. He will be discussed in this article. All sensor modes are configured by writing to specific EEPROM cells. By default, the sensor is in SMBus mode.
Appearance and connection diagram
. " " 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_ */
:
In conclusion, complete project listings
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;
}
delay.h
#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);
delay.c
#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
}