I2C LCD shows weird character - i2c

I am using a DS3231 timer circuit and a I2C lcd plus RELAY shield with arduino uno. My target is to turn on the relay according to pre-programmed time and showing the current time in the LCD.
The program works fine, except i have used a sub program named as WATCHMAN. The purpose of this sub program is to run the watch and show it in LCD. Problem is each time I plug it off and then after plugging on the whole hardware .. the LCD shows weird character instead of the CLOCK. What is the problem that is screwing up the LCD display?
Code is as below -
#include <SoftwareSerial.h>
SoftwareSerial SIM900A(9, 10);
#include <Wire.h>
#define ADDRESS 0x68
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
#define BACKLIGHT_PIN 13
void setup() {
Serial.begin(9600);
Wire.begin();
SIM900A.begin(9600);
delay(15);
lcd.begin(16,2);
delay(15);
pinMode(11,OUTPUT);
pinMode(12,OUTPUT);
pinMode ( BACKLIGHT_PIN, OUTPUT );
digitalWrite ( BACKLIGHT_PIN,HIGH);
}
void loop(){
delay(500);
Watchman();
int yrchk=Year();
int daychk=Date();
int mthchk=Month();
String mth=MonthString ();
int hrchk= (Hour())*100;
int minchk= Min();
int schk=(Sec())/100;
int convtime=hrchk+minchk+schk;
Serial.println(convtime);
if (yrchk>=2018 &&(mth=="January"|| mth=="February"|| mth=="March")){
if (convtime>=1810 && convtime<=2359){
Serial.println("First stage-1 loop is running");
digitalWrite(11,HIGH);
digitalWrite(12,HIGH);} // Turning on the relay pin no 11 & 12
else if ((convtime>=100 && convtime<=540)){digitalWrite(11,HIGH);digitalWrite(12,HIGH); // Turning on the relay pin no 11 & 12
Serial.println("First stage-2 loop is running");}
}
else if (yrchk>=2018 &&(mth=="April"|| mth=="May"|| mth=="June"|| mth=="July"|| mth=="August")){
if (convtime>=1830 && convtime<=2359){
Serial.println("second stage-1 loop is running");
digitalWrite(11,HIGH);digitalWrite(12,HIGH);} // Turning on the relay pin no 11 & 12
else if ((convtime>=100 && convtime<=520)){digitalWrite(11,HIGH);digitalWrite(12,HIGH);
Serial.println("second stage-2 loop is running");}
}
else if (yrchk>=2018 &&(mth=="September"|| mth=="October")){
if (convtime>=1750 && convtime<=2359){
Serial.println("Third stage-1 loop is running");
digitalWrite(11,HIGH); // Turning on the relay pin no 11 & 12
digitalWrite(12,HIGH);}
else if ((convtime>=100 && convtime<=540)){digitalWrite(11,HIGH);digitalWrite(12,HIGH);
Serial.println("Third stage-2 loop is running");}
}
else if (yrchk>=2018 &&(mth=="November"|| mth=="December")){
if (convtime>=1735 && convtime<=2359){
Serial.println("Fourth stage-1 loop is running");
digitalWrite(11,HIGH);digitalWrite(12,HIGH);} // Turning on the relay pin no 11 & 12
else if ((convtime>=100 && convtime<=600)){digitalWrite(11,HIGH);digitalWrite(12,HIGH);
Serial.println("Fourth stage-2 loop is running");}
}
else if (yrchk<2018){
//SIM900A.println("AT+CMGF=1");
//delay(1000);
//SIM900A.println("AT+CMGS=\"+8801714206279\"\r"); // Replace x with mobile number
//delay(1000);
//SIM900A.println("Out of date error in DS3231,send instruction");// The SMS text you want to send
//delay(100);
//SIM900A.println((char)26);// ASCII code of CTRL+Z
//delay(1000);
digitalWrite(11,LOW);
digitalWrite(12,LOW);
}
}
//void eepromWrite(int address, int location,int data)
//{
//Wire.beginTransmission(address);
//Wire.write(location);
//Wire.write(data);
//Wire.endTransmission();
//}
//byte eepromRead(byte location)
//{
//Wire.beginTransmission(ADDRESS);
//Wire.write(location);
//Wire.endTransmission();
//Wire.requestFrom(ADDRESS,25);
//while(!Wire.available()){}
//return Wire.read();
//}
String MonthString ()
{
Wire.beginTransmission(ADDRESS);
Wire.write(0x05);
Wire.endTransmission();
Wire.requestFrom(ADDRESS,1);
while(!Wire.available()){}
int i= Wire.read();
String k;
if (i==1){ k="January";};
if (i==2) {k="February";};
if (i==3) {k="March";};
if (i==4) {k="April";};
if (i==5) {k="May";};
if (i==6) {k="June";};
if (i==7) {k="July";};
if (i==8) {k="August";};
if (i==9) {k="September";};
if (i==10){k="October";};
if (i==11){k="November";};
if (i==12){k="December";};
return k;
}
int Month()
{
Wire.beginTransmission(ADDRESS);
Wire.write(0x05);
Wire.endTransmission();
Wire.requestFrom(ADDRESS,1);
while(!Wire.available()){}
int i= Wire.read();
return i;
}
byte Min()
{
Wire.beginTransmission(ADDRESS);
Wire.write(0x01);
Wire.endTransmission();
Wire.requestFrom(ADDRESS,2);
while(!Wire.available()){}
byte bcd_value = Wire.read(); // lets say bcd_value = 55, or 0x37
byte tens = bcd_value >> 4; // tens = 3 (by shifting down the number four places)
byte units = bcd_value & 0x0F; // units = 7 (the 0x0F filters-out the high digit)
byte final_value = (tens * 10) + units;
return final_value;
}
byte Hour()
{
Wire.beginTransmission(ADDRESS);
Wire.write(0x02);
Wire.endTransmission();
Wire.requestFrom(ADDRESS,1);
while(!Wire.available()){}
byte bcd_value = Wire.read(); // lets say bcd_value = 55, or 0x37
byte tens = bcd_value >> 4; // tens = 3 (by shifting down the number four places)
byte units = bcd_value & 0x0F; // units = 7 (the 0x0F filters-out the high digit)
byte final_value = (tens * 10) + units;
return final_value;
}
byte Date()
{
Wire.beginTransmission(ADDRESS);
Wire.write(0x04);
Wire.endTransmission();
Wire.requestFrom(ADDRESS,1);
while(!Wire.available()){}
byte bcd_value = Wire.read(); // lets say bcd_value = 55, or 0x37
byte tens = bcd_value >> 4; // tens = 3 (by shifting down the number four places)
byte units = bcd_value & 0x0F; // units = 7 (the 0x0F filters-out the high digit)
byte final_value = (tens * 10) + units;
return final_value;
}
int Year()
{
Wire.beginTransmission(ADDRESS);
Wire.write(0x06);
Wire.endTransmission();
Wire.requestFrom(ADDRESS,1);
while(!Wire.available()){}
byte bcd_value = Wire.read(); // lets say bcd_value = 55, or 0x37
byte tens = bcd_value >> 4; // tens = 3 (by shifting down the number four places)
byte units = bcd_value & 0x0F; // units = 7 (the 0x0F filters-out the high digit)
byte final_value =(tens * 10) + units;
int k= final_value+2000;
return k;
}
String DayString ()
{
Wire.beginTransmission(ADDRESS);
Wire.write(0x03);
Wire.endTransmission();
Wire.requestFrom(ADDRESS,1);
while(!Wire.available()){}
int i= Wire.read();
String k;
if (i==1){ k="Monday";};
if (i==2) {k="Tuesday";};
if (i==3) {k="Wednesday";};
if (i==4) {k="Thursday";};
if (i==5) {k="Friday";};
if (i==6) {k="Saturday";};
if (i==7) {k="Sunday";};
return k;
}
byte Sec()
{
Wire.beginTransmission(ADDRESS);
Wire.write(0x00);
Wire.endTransmission();
Wire.requestFrom(ADDRESS,2);
while(!Wire.available()){}
byte bcd_value = Wire.read(); // lets say bcd_value = 55, or 0x37
byte tens = bcd_value >> 4; // tens = 3 (by shifting down the number four places)
byte units = bcd_value & 0x0F; // units = 7 (the 0x0F filters-out the high digit)
byte final_value = (tens * 10) + units;
return final_value;
}
byte Temp()
{
Wire.beginTransmission(ADDRESS);
Wire.write(0x11);
Wire.endTransmission();
Wire.requestFrom(ADDRESS,1);
while(!Wire.available()){}
byte bcd_value = Wire.read(); // lets say bcd_value = 55, or 0x37
byte tens = bcd_value >> 4; // tens = 3 (by shifting down the number four places)
byte units = bcd_value & 0x0F; // units = 7 (the 0x0F filters-out the high digit)
byte final_value = (tens * 10) + units;
return final_value;
}
void Watchman()
{
byte hr=Hour();
byte mn=Min();
byte sc=Sec();
byte tm= Temp();
byte dt=Date();
byte mt=Month();
int yr=Year();
String o;
if(hr>12){o=" PM";}
else{o=" AM";}
if (hr>12){hr=Hour()-12;}
lcd.clear();
lcd.setCursor(4,0);
lcd.print(dt);
lcd.print("/");
lcd.print(mt);
lcd.print("/");
lcd.print(yr);
//Serial.println(yr);
lcd.setCursor(4,1);
lcd.print(hr);
lcd.print(".");
lcd.print(mn);
lcd.print(".");
lcd.print(sc);
lcd.print(o);
//lcd.print(",T=");
//lcd.print(tm);
delay(500);
}
//}
void Serialman()
{
byte hr=Hour();
byte mn=Min();
byte sc=Sec();
byte tm= Temp();
byte dt=Date();
byte mt=Month();
int yr=Year();
String o;
if(hr>12){o=" PM";}
else{o=" AM";}
if (hr>12){hr=Hour()-12;}
Serial.print(dt);
Serial.print("/");
Serial.print(mt);
Serial.print("/");
Serial.println(yr);
Serial.print(hr);
Serial.print(".");
Serial.print(mn);
Serial.print(".");
Serial.print(sc);
Serial.print(o);
Serial.print(",T=");
Serial.print(tm);
Serial.println("");}

Related

MCP79411 RTC connection via i2c/TWI interface on Atmel SAMG55

I've made a project based on ATSAMG55J19 MCU, programmed with Atmel Studio and ASF 3
Now i'm trying to add an external RTC clock, because internal SAMg55 rtc does not have a backup battery.
The module will be used to read current time after power failure, then i'll use internal RTC, so i need only basic communication. No need to write specific data in EEPROM or setting alarms.
I have a MCP79411, connected via i2c, but there aren't any library suitable for this MCU that uses ASF TWI library.
There are many Arduino implementation, but they uses Wire.h library, and i can't port it.
I made an attempt porting this simple "driver": https://www.ccsinfo.com/forum/viewtopic.php?t=54105
Here is some code
static void i2c_start(void){
static twi_options_t ext3_twi_options;
flexcom_enable(FLEXCOM4);
flexcom_set_opmode(FLEXCOM4, FLEXCOM_TWI);
ext3_twi_options.master_clk = sysclk_get_cpu_hz();
ext3_twi_options.speed = 100000;
ext3_twi_options.smbus = 0;
twi_master_init(TWI4, &ext3_twi_options);
}
// Init Real Time Clock
void rtc_Init(void)
{
uint8_t seconds = 0;
i2c_start();
twi_write_byte(TWI4, ADDR_RTCC_WRITE); // WR to RTC
twi_write_byte(TWI4, ADDR_SEC); // REG 0
twi_write_byte(TWI4, ADDR_RTCC_READ); // RD from RTC
seconds = bcd2bin(i2c_read(0)); // Read current "seconds" in rtc
//i2c_stop();
//seconds &= 0x7F;
seconds |= 0x80; //set to 1 bit 7 of seconds(ST) enabling oscillator
delay_us(3);
twi_write_byte(TWI4, ADDR_RTCC_WRITE); // WR to RTC
twi_write_byte(TWI4, ADDR_SEC); // REG 0
twi_write_byte(TWI4, bin2bcd(seconds) | 0x80); // Start oscillator with current "seconds value
twi_write_byte(TWI4, ADDR_RTCC_WRITE); // WR to RTC
twi_write_byte(TWI4, 0x07); // Control Register
twi_write_byte(TWI4, 0x80); // Disable squarewave output pin
//i2c_stop();
}
Then i tried rtc_set_date_time(uint8_t day, uint8_t mth, uint8_t year, uint8_t dow, uint8_t hr, uint8_t min, uint8_t sec)
and
void rtc_get_time(uint8_t &hr, uint8_t &min, uint8_t &sec)
{
twi_write_byte(TWI4, ADDR_RTCC_WRITE);
twi_write_byte(TWI4, 0x00);
twi_write_byte(TWI4, ADDR_RTCC_READ);
sec = bcd2bin(twi_read_byte(TWI4) & 0x7f); //0x7f b01111111
min = bcd2bin(twi_read_byte(TWI4) & 0x7f); //0x7f
hr = bcd2bin(twi_read_byte(TWI4) & 0x3f); //0x3f b00111111
//i2c_stop();
}
But i always get "0" bytes.
i could not understand the correct way to open communication and read bytes from i2c.
The only reference i found is http://asf.atmel.com/docs/latest/sam.drivers.twi.twi_eeprom_example.samg53_xplained_pro/html/index.html but it seems to be a very different type of communication.
What is the correct way to send and receive that bytes via i2c?
I managed to get and set data. I post a draft of library:
#include "asf.h"
#include "conf_board_3in4out.h"
#include "external_rtc.h"
#include <time.h>
//#include <time_utils.h>
twi_packet_t packet_tx, packet_rx;
// helper functions to manipulate BCD and binary to integers
static int bcd2dec(char r_char)
{
MSN = (r_char & 0xF0)/16;
LSN = r_char & 0x0F;
return(10*MSN + LSN);
}
static char msn(char tim)
{
return (tim & 0xF0)/16;
}
static char lsn(char tim)
{
return (tim & 0x0F);
}
#define RTC_ADDR 0x6F // 7 bits
char config_t[10];
char config_2[8];
char tim_read[8];
#define ADDR_SEC 0x00 // address of SECONDS register
#define ADDR_MIN 0x01 // address of MINUTES register
#define ADDR_HOUR 0x02 // address of HOURS register
#define ADDR_DAY 0x03 // address of DAY OF WEEK register
#define ADDR_STAT 0x03 // address of STATUS register
#define ADDR_DATE 0x04 // address of DATE register
#define ADDR_MNTH 0x05 // address of MONTH register
#define ADDR_YEAR 0x06 // address of YEAR register
#define ADDR_CTRL 0x07 // address of CONTROL register
#define ADDR_CAL 0x08 // address of CALIB register
#define ADDR_ULID 0x09 // address of UNLOCK ID register
#define ADDR_SAVtoBAT_MIN 0x18 // address of T_SAVER MIN(VDD->BAT)
#define ADDR_SAVtoBAT_HR 0x19 // address of T_SAVER HR (VDD->BAT)
#define ADDR_SAVtoBAT_DAT 0x1a // address of T_SAVER DAT(VDD->BAT)
#define ADDR_SAVtoBAT_MTH 0x1b // address of T_SAVER MTH(VDD->BAT)
#define START_32KHZ 0x80 // start crystal: ST = b7 (ADDR_SEC)
#define OSCON 0x20 // state of the oscillator(running or not)
#define VBATEN 0x08 // enable battery for back-up
static uint8_t bin2bcd(uint8_t binary_value)
{
uint8_t temp;
uint8_t retval;
temp = binary_value;
retval = 0;
if(temp >= 10)
{
temp -= 10;
retval += 0x10;
}
else
{
retval += temp;
//break;
}
return(retval);
}
static uint8_t bcd2bin(uint8_t bcd_value)
{
uint8_t temp;
temp = bcd_value;
temp >>= 1;
temp &= 0x78;
return(temp + (temp >> 2) + (bcd_value & 0x0f));
}
static void setConfig(void){
config_2[0] = tim_read[0] | START_32KHZ; // bitwise OR sets Start osc bit = 1
config_2[1] = tim_read[1];
config_2[2] = tim_read[2];
//0x03h – Contains the BCD day. The range is 1-7.
//Bit 3 is the VBATEN bit. If this bit is set, the
//internal circuitry is connected to the VBAT pin
//when VCC fails. If this bit is ‘0’ then the VBAT pin is
//disconnected and the only current drain on the
//external battery is the VBAT pin leakage.
config_2[3] = tim_read[3] | VBATEN;
config_2[4] = tim_read[4];
config_2[5] = tim_read[5];
config_2[6] = tim_read[6];
config_2[7] = 0x00; // control b3 - extosc = 0
}
static void initialize(void){
uint8_t buf[7]; // Fill this with RTC clock data for all seven registers
// read stored time data
config_t[0] = 0x00; //reset pointer reg to '00'
// Set up config to read the time and set the control bits
//i2c.write(addr, config_t, 1); // write address 00
packet_tx.chip = RTC_ADDR;
packet_tx.addr[0] = 0; // RTCSEC
packet_tx.addr_length = 1;
packet_tx.buffer = config_t;
packet_tx.length = 1;
twi_master_write(TWI4, &packet_tx);
delay_ms(250);
//
//i2c.read(addr, tim_read, 7); //read time ss mm hh from r1, r2, r3
packet_rx.chip = RTC_ADDR;
packet_rx.addr[0] = 0; // RTCSEC
packet_rx.addr_length = 1;
packet_rx.buffer = tim_read;
packet_rx.length = sizeof(tim_read);
twi_master_read(TWI4, &packet_rx);
delay_ms(250);
setConfig(); //puts RTCC data into config array from tim_read array
// write the config data
//i2c.write(addr, config_t, 9); // write the config data back to the RTCC module
packet_tx.chip = RTC_ADDR;
packet_tx.addr[0] = 0; // RTCSEC
packet_tx.addr_length = 1;
packet_tx.buffer = config_2;
packet_tx.length = sizeof(config_2);
twi_master_write(TWI4, &packet_tx);
}
static void write_time(void){
// re-calculate mins
mins = 8; //ORE 10:08
mins = mins%60;
ch_mins = 16*(mins/10) + mins%10;
MSN = msn(ch_mins);
LSN = lsn(ch_mins);
tim_read[1] = ch_mins;
inc_mins = 0;
//write the data back to RTCC
setConfig();
//i2c.write(addr, config_t, 9);
/* Configure the data packet to be transmitted */
packet_tx.chip = RTC_ADDR;
packet_tx.addr[0] = 0; // RTCSEC
packet_tx.addr_length = 1;
packet_tx.buffer = config_2;
packet_tx.length = sizeof(config_2);
twi_master_write(TWI4, &packet_tx);
//Display and set hours
//hrs = bcd2dec(tim_read[2]);
// re-calculate hrs
hrs = 10; //ORE 10:08
hrs = hrs%24;
ch_hrs = 16*(hrs/10) + hrs%10;
MSN = msn(ch_hrs);
LSN = lsn(ch_hrs);
tim_read[2] = ch_hrs;
inc_hr = 0;
//write the data back to RTCC
setConfig();
/* Configure the data packet to be transmitted */
packet_tx.chip = RTC_ADDR;
packet_tx.addr[0] = 0; // RTCSEC
packet_tx.addr_length = 1;
packet_tx.buffer = config_2;
packet_tx.length = sizeof(config_2);
twi_master_write(TWI4, &packet_tx);
}
static void read_time(void){
//config_t[0] = 0x00; //reset pointer reg to '00'
//// First Get the time
////i2c.write(addr, config_t, 1); // write address 00
//packet_tx.chip = RTC_ADDR;
//packet_tx.addr[0] = 0; // RTCSEC
//packet_tx.addr_length = 1;
//packet_tx.buffer = config_t;
//packet_tx.length = 1;
//
//twi_master_write(TWI4, &packet_tx);
delay_ms(250);
uint8_t buf[7]; // Fill this with RTC clock data for all seven registers
/* Configure the data packet to be received */
packet_rx.chip = RTC_ADDR;
packet_rx.addr[0] = 0; // RTCSEC
packet_rx.addr_length = 1;
packet_rx.buffer = buf;
packet_rx.length = sizeof(buf);
twi_master_read(TWI4, &packet_rx);
for(uint8_t i = 0; i < sizeof(buf); i++){
tim_read[i] = buf[i];
}
}
void example_print_time(void){
//initialize();
delay_ms(1000);
//write_time(); //commented to see if time is permanent
delay_ms(1000);
read_time();
while(1){
printf("Reading time\n");
printf("%d:%d:%d\n", bcd2dec(tim_read[2]), bcd2dec(tim_read[1]), bcd2dec(tim_read[0] ^ START_32KHZ));
delay_ms(1000);
read_time();
}
}

How can I pack a float3 into one float

I am doing some animation jobs. I need to pack some pivots into UV and then my shader can read them.
I need to pack 4 float3 into a float4. Therefore, I need to pack each float3 into a float.
These 4 float3 are (model space position1, direction1, model space position2, direction2). I know how to handle the directions because they are normalized. I can use something like:
#define f3_f(c) (dot(round((c) * 255), float3(65536, 256, 1)))
#define f_f3(f) (frac((f) / float3(16777216, 65536, 256)))
But how can I handle positions? I am using SM3.0 and I can't use bitwise operation.
Do you really need to pack it into a float (4 bytes), or can you pack it into a 32-bit unsigned integer (i.e. 4 bytes)?
If, so take a look at the code in DirectXMath for converting to/from various formats as done in DirectXTex such as DXGI_FORMAT_R11G11B10_FLOAT. Since this format is positive only, you'll have to do a scale and bias to/from the format to handle the [-1,+1] range, but that's easy to do (0.5*value + 0.5 <-> 2*value - 1).
// 3D vector: 11/11/10 floating-point components
// The 3D vector is packed into 32 bits as follows: a 5-bit biased exponent
// and 6-bit mantissa for x component, a 5-bit biased exponent and
// 6-bit mantissa for y component, a 5-bit biased exponent and a 5-bit
// mantissa for z. The z component is stored in the most significant bits
// and the x component in the least significant bits. No sign bits so
// all partial-precision numbers are positive.
// (Z10Y11X11): [32] ZZZZZzzz zzzYYYYY yyyyyyXX XXXxxxxx [0]
struct XMFLOAT3PK
{
union
{
struct
{
uint32_t xm : 6; // x-mantissa
uint32_t xe : 5; // x-exponent
uint32_t ym : 6; // y-mantissa
uint32_t ye : 5; // y-exponent
uint32_t zm : 5; // z-mantissa
uint32_t ze : 5; // z-exponent
};
uint32_t v;
};
XMFLOAT3PK() = default;
XMFLOAT3PK(const XMFLOAT3PK&) = default;
XMFLOAT3PK& operator=(const XMFLOAT3PK&) = default;
XMFLOAT3PK(XMFLOAT3PK&&) = default;
XMFLOAT3PK& operator=(XMFLOAT3PK&&) = default;
explicit XM_CONSTEXPR XMFLOAT3PK(uint32_t Packed) : v(Packed) {}
XMFLOAT3PK(float _x, float _y, float _z);
explicit XMFLOAT3PK(_In_reads_(3) const float *pArray);
operator uint32_t () const { return v; }
XMFLOAT3PK& operator= (uint32_t Packed) { v = Packed; return *this; }
};
// Converts float3 to the 11/11/10 format
inline void XM_CALLCONV XMStoreFloat3PK
(
XMFLOAT3PK* pDestination,
FXMVECTOR V
)
{
assert(pDestination);
__declspec(align(16)) uint32_t IValue[4];
XMStoreFloat3A( reinterpret_cast<XMFLOAT3A*>(&IValue), V );
uint32_t Result[3];
// X & Y Channels (5-bit exponent, 6-bit mantissa)
for(uint32_t j=0; j < 2; ++j)
{
uint32_t Sign = IValue[j] & 0x80000000;
uint32_t I = IValue[j] & 0x7FFFFFFF;
if ((I & 0x7F800000) == 0x7F800000)
{
// INF or NAN
Result[j] = 0x7c0;
if (( I & 0x7FFFFF ) != 0)
{
Result[j] = 0x7c0 | (((I>>17)|(I>>11)|(I>>6)|(I))&0x3f);
}
else if ( Sign )
{
// -INF is clamped to 0 since 3PK is positive only
Result[j] = 0;
}
}
else if ( Sign )
{
// 3PK is positive only, so clamp to zero
Result[j] = 0;
}
else if (I > 0x477E0000U)
{
// The number is too large to be represented as a float11, set to max
Result[j] = 0x7BF;
}
else
{
if (I < 0x38800000U)
{
// The number is too small to be represented as a normalized float11
// Convert it to a denormalized value.
uint32_t Shift = 113U - (I >> 23U);
I = (0x800000U | (I & 0x7FFFFFU)) >> Shift;
}
else
{
// Rebias the exponent to represent the value as a normalized float11
I += 0xC8000000U;
}
Result[j] = ((I + 0xFFFFU + ((I >> 17U) & 1U)) >> 17U)&0x7ffU;
}
}
// Z Channel (5-bit exponent, 5-bit mantissa)
uint32_t Sign = IValue[2] & 0x80000000;
uint32_t I = IValue[2] & 0x7FFFFFFF;
if ((I & 0x7F800000) == 0x7F800000)
{
// INF or NAN
Result[2] = 0x3e0;
if ( I & 0x7FFFFF )
{
Result[2] = 0x3e0 | (((I>>18)|(I>>13)|(I>>3)|(I))&0x1f);
}
else if ( Sign )
{
// -INF is clamped to 0 since 3PK is positive only
Result[2] = 0;
}
}
else if ( Sign )
{
// 3PK is positive only, so clamp to zero
Result[2] = 0;
}
else if (I > 0x477C0000U)
{
// The number is too large to be represented as a float10, set to max
Result[2] = 0x3df;
}
else
{
if (I < 0x38800000U)
{
// The number is too small to be represented as a normalized float10
// Convert it to a denormalized value.
uint32_t Shift = 113U - (I >> 23U);
I = (0x800000U | (I & 0x7FFFFFU)) >> Shift;
}
else
{
// Rebias the exponent to represent the value as a normalized float10
I += 0xC8000000U;
}
Result[2] = ((I + 0x1FFFFU + ((I >> 18U) & 1U)) >> 18U)&0x3ffU;
}
// Pack Result into memory
pDestination->v = (Result[0] & 0x7ff)
| ( (Result[1] & 0x7ff) << 11 )
| ( (Result[2] & 0x3ff) << 22 );
}
// Converts the 11/11/10 format to float3
inline XMVECTOR XM_CALLCONV XMLoadFloat3PK
(
const XMFLOAT3PK* pSource
)
{
assert(pSource);
__declspec(align(16)) uint32_t Result[4];
uint32_t Mantissa;
uint32_t Exponent;
// X Channel (6-bit mantissa)
Mantissa = pSource->xm;
if ( pSource->xe == 0x1f ) // INF or NAN
{
Result[0] = static_cast<uint32_t>(0x7f800000 | (static_cast<int>(pSource->xm) << 17));
}
else
{
if ( pSource->xe != 0 ) // The value is normalized
{
Exponent = pSource->xe;
}
else if (Mantissa != 0) // The value is denormalized
{
// Normalize the value in the resulting float
Exponent = 1;
do
{
Exponent--;
Mantissa <<= 1;
} while ((Mantissa & 0x40) == 0);
Mantissa &= 0x3F;
}
else // The value is zero
{
Exponent = static_cast<uint32_t>(-112);
}
Result[0] = ((Exponent + 112) << 23) | (Mantissa << 17);
}
// Y Channel (6-bit mantissa)
Mantissa = pSource->ym;
if ( pSource->ye == 0x1f ) // INF or NAN
{
Result[1] = static_cast<uint32_t>(0x7f800000 | (static_cast<int>(pSource->ym) << 17));
}
else
{
if ( pSource->ye != 0 ) // The value is normalized
{
Exponent = pSource->ye;
}
else if (Mantissa != 0) // The value is denormalized
{
// Normalize the value in the resulting float
Exponent = 1;
do
{
Exponent--;
Mantissa <<= 1;
} while ((Mantissa & 0x40) == 0);
Mantissa &= 0x3F;
}
else // The value is zero
{
Exponent = static_cast<uint32_t>(-112);
}
Result[1] = ((Exponent + 112) << 23) | (Mantissa << 17);
}
// Z Channel (5-bit mantissa)
Mantissa = pSource->zm;
if ( pSource->ze == 0x1f ) // INF or NAN
{
Result[2] = static_cast<uint32_t>(0x7f800000 | (static_cast<int>(pSource->zm) << 17));
}
else
{
if ( pSource->ze != 0 ) // The value is normalized
{
Exponent = pSource->ze;
}
else if (Mantissa != 0) // The value is denormalized
{
// Normalize the value in the resulting float
Exponent = 1;
do
{
Exponent--;
Mantissa <<= 1;
} while ((Mantissa & 0x20) == 0);
Mantissa &= 0x1F;
}
else // The value is zero
{
Exponent = static_cast<uint32_t>(-112);
}
Result[2] = ((Exponent + 112) << 23) | (Mantissa << 18);
}
return XMLoadFloat3A( reinterpret_cast<const XMFLOAT3A*>(&Result) );
}

STM32F103C8T6 can not communicate with HD44780

I'm trying to control a HD44780 16X2 LCD(4 bit
communication) using a STM32F103C8T6.
I connected the LCD this way:
RS => PA0
EN => PA2
RW Ground
D7 => PB7
D6 => PB6
D5 => PB5
D4 => PB4
The LCD doesn't display anything. Where might the problem be? Does anyone know something about this issue?
Here is my code:
#include "delay.h"
#include "stm32f10x.h" // Device header
void lcd_command(unsigned char command);
void lcd_init(void);
void lcdPosition(unsigned int row, unsigned int column);
void lcd_data(unsigned char data);
int main() {
delay_init();
RCC->APB2ENR |= 1 << 2; // Port A Enabled.
RCC->APB2ENR |= 1 << 3; // Port B Enabled.
GPIOA->CRL = 0x22222222; // A0 and A2 Output.
GPIOB->CRL = 0x22222222; // B7,B6,B5,B4 Output.
GPIOB->ODR = 0x00; // Port B clear.
delay_ms(20);
lcd_command(0x30); // Datasheet says.
delay_ms(5);
lcd_command(0x30); // Datasheet says.
delay_ms(1);
lcd_command(0x30); // Datasheet says.
delay_ms(1);
lcd_init();
lcdPosition(1, 1); // first row first column
delay_ms(1);
lcd_data('A'); // Letter A
while (1)
;
}
void lcd_command(unsigned char command) {
GPIOA->BRR |= 1 << 0; // RS reset.
GPIOA->BSRR |= 1 << 2; // E set.
GPIOB->ODR = command; // upper nibble
delay_ms(2); // delay
GPIOA->BRR |= 1 << 2; // E reset.
GPIOB->BRR = 0x000000F0; // clear data bits
delay_ms(2); // delay
command = command << 4; // lower nibble
GPIOA->BSRR |= 1 << 2; // E set.
GPIOB->ODR = command; // lower nibble
delay_ms(2); // delay
GPIOA->BRR |= 1 << 2; // E reset.
GPIOB->BRR = 0x000000FF; // clear data bits
}
void lcd_init() {
lcd_command(0x02); // Return
delay_ms(2); // delay
lcd_command(0x28);
set 4 - bit data, 2 - line, 5x7 font delay_ms(2); // delay
lcd_command(0x0C);
turn on display, cursor off.delay_ms(2); // delay
lcd_command(0x01); // Clear.
delay_ms(2); // delay
lcd_command(0x06);
move cursor right delay_ms(4); // delay
}
void lcdPosition(unsigned int row, unsigned int column) {
if (row == 1) {
column--;
lcd_command(0x80 + column); // Define row
} else if (row == 2) {
column--;
lcd_command(0xC0 + column); // Define column
}
}
void lcd_data(unsigned char data) {
GPIOA->BSRR |= 1 << 0; // RS reset.
GPIOA->BSRR |= 1 << 2; // E set.
GPIOB->ODR = data;
upper nibble first delay_ms(4); // delay
GPIOA->BRR |= 1 << 2; // E reset.
GPIOB->BRR = 0x000000F0; // clear data bits
delay_ms(4); // delay
data = data << 4; // lower nibble
GPIOA->BSRR |= 1 << 2; // E set.
GPIOB->ODR = data; // lower nibble
delay_ms(4); // delay
GPIOA->BRR |= 1 << 2; // E reset.
GPIOB->BRR = 0x000000FF; // clear data bits
}
Also PA0 and PA2 are not 5V tolerant pins, usually HD44780 is 5V device, if it runs on +5V refer to the datasheet in Table 5. "Medium-density STM32F103xx pin definitions", if the pin is 5V tolerant in column I/O level it should be denoted with FT!
Please read carefully how to initialize 4-bit interface in the datasheet at page 46, figure 24.
In short: your lcd_command sends two nibbles one after another, but you are required to send only one nibble for first several commands (since the display controller still is in the 8-bit mode). You'll need to have a separate function to send only one nibble.

Error using serial/fopen (line 72) MATLAB

I am using a pressure sensor D6F-PH to measure the pressure difference. This is my Arduino code that I wrote to get the values from the sensor.
#include "Wire.h"
#define addrs 0x6C // I2C bus address
int P;
int I;
float T;c
int initialize(int i2c_addr)
{
//INITIALIZATION AFTER POWER UP
Wire.beginTransmission(i2c_addr);
Wire.write(0x0B);
Wire.write(0x00);
int x = Wire.endTransmission();
return x;
}
int pressure(int i2c_addr)
{
//MCU MODE
Wire.beginTransmission(i2c_addr);
Wire.write(0x00);
Wire.write(0xD0); // reg 0 - address register high byte
// Wire.write(0x51); // reg 1 - address register low byte
Wire.write(0x40); // reg 1 - address register low byte
Wire.write(0x18); // reg 2 - serial control register - indicate # bytes among others (page 7 bottom)
Wire.write(0x06); // reg 3 - value to be written to SENS control register
int x = Wire.endTransmission();
delay(33);
//WRITE
Wire.beginTransmission(i2c_addr);
Wire.write(0x00);
Wire.write(0xD0);
Wire.write(0x51);
Wire.write(0x2C);
x = Wire.endTransmission();
//READ
Wire.beginTransmission(i2c_addr);
Wire.write(0x07);
x = Wire.endTransmission();
Wire.requestFrom(i2c_addr, 2);
byte hibyte = Wire.read();
byte lobyte = Wire.read();
long raw = word( hibyte, lobyte);
//Serial.print("raw pressure:\t ");
Serial.println(raw);
// D6F-PH5050AD3 ==> rangeMode=500 ==> int rd_pressure = ((raw - 1024) * rangeMode * 2 / 60000L) - rangeMode
// D6F-PH0505AD3 ==> rangeMode=50 ==> int rd_pressure = ((raw - 1024) * rangeMode * 2 / 60000L) - rangeMode
// D6F-PH0025AD1 ==> rangeMode=250 ==> int rd_pressure=(raw - 1024) * rangeMode / 60000L
//int rangeMode = 50;
int rangeMode = 250;
int rd_pressure = (raw - 1024) * rangeMode / 60000L;
//int rd_pressure = ((raw - 1024) * rangeMode * 10/60000L) - rangeMode;
return rd_pressure;
}
float temperature(int i2c_addr)
{
//MCU MODE
Wire.beginTransmission(i2c_addr);
Wire.write(0x00);
Wire.write(0xD0); // reg 0 - address register high byte
// Wire.write(0x51); // reg 1 - address register low byte
Wire.write(0x40); // reg 1 - address register low byte
Wire.write(0x18); // reg 2 - serial control register - indicate # bytes among others (page 7 bottom)
Wire.write(0x06); // reg 3 - value to be written to SENS control register
int x = Wire.endTransmission();
delay(33);
//WRITE
Wire.beginTransmission(i2c_addr);
Wire.write(0x00);
Wire.write(0xD0);
Wire.write(0x61);
Wire.write(0x2C);
x = Wire.endTransmission();
//READ
Wire.beginTransmission(i2c_addr);
Wire.write(0x07);
x = Wire.endTransmission();
Wire.requestFrom(i2c_addr, 2);
byte hibyte = Wire.read();
byte lobyte = Wire.read();
long raw = word( hibyte, lobyte);
//Serial.print("raw temperature:\t ");
//Serial.println(raw);
int temp = round((float)(raw - 10214) / 3.739); // this is the temperature multiplied by 10...
return (temp / 10.0); // ...and the function returs the float
temperature with 0.1°C resolution
}
void setup()
{ // Open serial communications
Wire.begin();
Serial.begin(9600);
I = initialize (addrs); // start wire connection
}
void loop()
{
P = pressure(addrs);
Serial.print("pressure:\t ");
Serial.println(P);
T = temperature(addrs);
Serial.print("temperature:\t ");
Serial.println(T);
delay(300); //delay for 30 seconds
}
I can measure the pressure and the temperature from the arduino uno board using the Serial Monitor.
When I try to Retrieve the data using MATLAB I am unable to do so.
s=serial('COM6','BaudRate',9600);
fopen(s);
This is the error message that I get when I try to open the port : Error using serial/fopen (line 72)
Open failed: Cannot connect to the COM2 port. Possible reasons are another
application is connected to the port or the port does not exist.
I have checked the COM port number and also used the delete(instrfindall); command but to no avail.
Please help
Resolved. I needed to close the Serial Monitor before creating a connection with MATLAB.

Creating a packet as a string and then extracted its fields in C

I need to implement my own packets to send over UDP. I decided that I would do this by sending a char buffer which has the sequence number, checksum, size, and the data of the packet which is bytes from a file. The string i'm sending separates each field by a semicolon. Then, when I receive the string (which is my packet) I want to extract each felid, use them accordingly (the sequence number, size, and checksum) and write the bytes to a file. So far I have wrote a method to create 100 packets, and I'm trying to extract and write the bytes to a file (I'm not doing it in the receiver yet, first I'm testing the parsing in the sender). For some reason, the bytes written to my file are incorrect and I'm getting "JPEG DATATSTREAM CONTAINS NO IMAGE" error when I try to open it.
struct packetNode{
char packet[1052]; // this is the entire packet data including the header
struct packetNode *next;
};
This is how I'm creating my packets:
//populate initial window of size 100
for(i = 0; i < 100; i++){
memset(&data[0], 0, sizeof(data));
struct packetNode *p; // create packet node
p = (struct packetNode *)malloc(sizeof(struct packetNode));
bytes = fread(data, 1, sizeof(data), fp); // read 1024 bytes from file into data buffer
int b = fwrite(data, 1, bytes, fpNew);
printf("read: %d\n", bytes);
memset(&p->packet[0], 0, sizeof(p->packet));
sprintf(p->packet, "%d;%d;%d;%s", s, 0, numPackets, data); // create packet
//calculate checksum
int check = checksum8(p->packet, sizeof(p->packet));
sprintf(p->packet, "%d;%d;%d;%s", s, check, numPackets, data); //put checksum in packet
s++; //incremenet sequence number
if(i == 0){
head = p;
tail = p;
tail->next = NULL;
}
else{
tail->next = p;
tail = p;
tail->next = NULL;
}
}
fclose(fp);
and this is where I parse and write the bytes to a file:
void test(){
FILE *fpNew = fopen("test.jpg", "w");
struct packetNode *ptr = head;
char *tokens;
int s, c, size;
int i = 0;
char data[1024];
while(ptr != NULL){
memset(&data[0], 0, sizeof(data));
tokens = strtok(ptr->packet,";");
s = atoi(tokens);
tokens = strtok(NULL, ";");
c = atoi(tokens);
tokens = strtok(NULL, ";");
size = atoi(tokens);
tokens = strtok(NULL, ";");
if(tokens != NULL)
strcpy(data, tokens);
printf("sequence: %d, checksum: %d, size: %d\n", s,c,size);
int b = fwrite(data, 1, sizeof(data), fpNew);
ptr = ptr->next;
i++;
}
fclose(fpNew);
}
Since there is transfer of binary data, a JPEG stream, this data cannot be treated as a string. It's better to go all binary. For instance, instead of
sprintf(p->packet, "%d;%d;%d;%s", s, 0, numPackets, data); // create packet
you would do
sprintf(p->packet, "%d;%d;%d;", s, 0, numPackets);
memcpy(&p->packet[strlen(p->packet)], data, bytes);
but this leads to parsing problems: we would need to change this:
tokens = strtok(NULL, ";");
if(tokens != NULL)
strcpy(data, tokens);
to something like this:
tokens += 1 + ( size < 10 ? 1 : size < 100 ? 2 : size < 1000 ? 3 : size < 10000 ? 4 : 5 );
memcpy(data, tokens, sizeof(data));
#Binary Protocol
It's easier to use a binary packet:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma push(pack,1)
typedef struct Packet {
int seq, maxseq, size;
unsigned short cksum;
unsigned char payload[];
} Packet;
#pragma pop(pack)
typedef struct PacketNode{
struct PacketNode * next;
Packet packet;
} PacketNode;
PacketNode * allocPacketNode(int maxPayloadSize) {
void * ptr = malloc(sizeof(PacketNode) + maxPayloadSize); // FIXME: error checking
memset(ptr, 0, sizeof(PacketNode) + maxPayloadSize); // mallocz wouldn't cooperate
return (PacketNode*) ptr;
}
PacketNode * prepare(FILE * fp, int fsize, int chunksize)
{
PacketNode * head = allocPacketNode(chunksize);
PacketNode * pn = head;
int rd, seq = 0;
int maxseq = fsize / chunksize + ( fsize % chunksize ? 1 : 0 );
while ( ( rd = fread(pn->packet.payload, 1, chunksize, fp ) ) > 0 )
{
printf("read %d bytes\n", rd);
pn->packet.seq = seq++;
pn->packet.maxseq = maxseq;
pn->packet.size = rd + sizeof(Packet);
pn->packet.cksum = 0;
pn->packet.cksum = ~checksum(&pn->packet, pn->packet.size);
if ( rd == chunksize )
pn = pn->next = allocPacketNode(chunksize);
}
return head;
}
int checksum(unsigned char * data, int len)
{
int sum = 0, i;
for ( i = 0; i < len; i ++ )
sum += data[i];
if ( sum > 0xffff )
sum = (sum & 0xffff) + (sum>>16);
return sum;
}
void test( PacketNode * ptr ) {
FILE *fpNew = fopen("test.jpg", "w");
while (ptr != NULL)
{
printf("sequence: %d/%d, checksum: %04x, size: %d\n",
ptr->packet.seq,
ptr->packet.maxseq,
ptr->packet.cksum,
ptr->packet.size - sizeof(Packet)
);
int b = fwrite(ptr->packet.payload, ptr->packet.size - sizeof(Packet), 1, fpNew);
ptr = ptr->next;
}
fclose(fpNew);
}
void fatal( const char * msg ) { printf("FATAL: %s\n", msg); exit(1); }
int main(int argc, char** argv)
{
if ( ! argv[1] ) fatal( "missing filename argument" );
FILE * fp = fopen( argv[1], "r" );
if ( ! fp ) fatal( "cannot open file" );
fseek( fp, 0, SEEK_END );
long fsize = ftell(fp);
fseek( fp, 0, SEEK_SET );
printf("Filesize: %d\n", fsize );
test( prepare(fp, fsize, 1024) );
}
The #pragma push(pack,1) changes how the compiler aligns fields of the struct. We want them to be compact, for network transport. Using 1 is byte-aligned. The #pragma pop(pack) restores the previous setting of the pack pragma.
A note on the checksum method
First we calculate the sum of all the bytes in the packet:
int sum = 0, i;
for ( i = 0; i < len; i ++ )
sum += data[i];
Since the packet uses an unsigned short (16 bits, max value 65535 or 0xffff) to store the checksum, we make sure that the result will fit:
if ( sum > 0xffff ) // takes up more than 16 bits.
Getting the low 16 bits of this int is done using sum & 0xffff, masking out everything but the low 16 bits. We could simply return this value, but we would loose the information from higher checksum bits. So, we will add the upper 16 bits to the lower 16 bits. Accessing the higher 16 bits is done by shifting the int to the right 16 bits, like so: sum >> 16. This is the same as sum / 65536, since 65536 = 216 = 1 << 16.
sum = (sum & 0xffff) + (sum>>16); // add low 16 bits and high 16 bits
I should note that network packet checksums are usually computed 2 bytes (or 'octets' as they like to call them there) at a time. For that, the data should be cast to an unsigned short *, and len should be divided by 2. However! len may be odd, so in that case we'll need to take special care of the last byte. For instance, assuming that the maximum packet size is even, and that the len argument is always <= max_packet_size:
unsigned short * in = (unsigned short *) data;
if ( len & 1 ) data[len] = 0; // make sure last byte is 0
len = (len + 1) / 2;
The rest of the checksum method can remain the same, except that it should operate on in instead of data.