I need to transfer data serially from AT89s52 to Hyperterminal of PC.
For that I made a sample program to print "Hello" on the hyperterminal of my PC by programming the below given code inside 89s52 microcontroller and connecting it to my PC via serial port. Now when I am opening hyperterminal for the respective port, I should be seeing "Hello" printed on the screen multiple times, but what actually I am seeing is some garbage data getting printed.
This is the code I have used.
#include < AT89X52.H>
#include < STDLIB.H>
#include < STDIO.H>
unsigned int i;
void main (void)
{
TMOD = 0x20;
SCON = 0x50;
TH1 = 0xFD;
TL1 = 0xFD;
TR1 = 1;
TI = 1;
P1 = 0;
while (1)
{
puts("Hello\r");
P1 ^= 0x01; /* Toggle P1.0 each time we print */
for(i=0;i<25000;i++);
}
}
In the Hyper terminal I am not getting correct output i.e. Hello. Instead I am seeing some Garbage characters..
Can anybody help on this please..?
Can you See P1 is toggling? I would rather send a single character first and observe what is sending by using an oscilloscope. You should see a digital signal corresponding to the ASCII value of the character being split-out from the TX pin of the micro. Also you can check the baud rate (exact value) by using the scope. If you are convinced that the correct value is sent at the right baud rate it is most likely that you got a bad connection or perhaps the baud rate should slightly be changed.
Related
I am using NodeMCU & Energy meter. Energy meter is Modbus RTU device which display parameter in 32 bit. With below piece of code I could able to read the data from slave but need method to type cast from into 32 bit floating & display
When I change the value to unsigned decimal in ModScan software the values showing properly. But I need to display value in 32 bit floating point.
#include <ModbusMaster232.h>
#include <SoftwareSerial.h>
float data[100];
ModbusMaster232 node(1);
// Define one address for reading
#define address 1
// Define the number of bits to read
#define bitQty 70
void setup()
{
Serial.begin(9600);
// Initialize Modbus communication baud rate
node.begin(9600);
}
void loop()
{
int result = node.readHoldingRegisters(address, bitQty);
data[0] = (float)node.getResponseBuffer(0);
data[1] = (float)node.getResponseBuffer(1);
data[2] = (float)node.getResponseBuffer(2);
data[3] = (float)node.getResponseBuffer(3);
data[4] = (float)node.getResponseBuffer(4);
data[5] = (float)node.getResponseBuffer(5);
for (int i = 0; i < 100; i++)
{
//data[i] = node.getResponseBuffer(i);
Serial.println(data[i]);
}
Serial.println("............");
}
I would like to display the reading as shown in Modbus with type casting.
Actual Modbus device output from salve:
Arduino output while read data from energy meter:
You are casting a 16-bit word into a float. Check the slave documentation to find how they map a 32-bit floating point into two Modbus registers. Basically you need to know where the least significant word is (first or second register), load them into memory (shift if necessary) and cast to float.
I am looking and trying to solve exact same problem (with same results). This may help:
function read() {
client.readHoldingRegisters(0000, 12)
.then(function(d) {
var floatA = d.buffer.readFloatBE(0);
console.log("Total kWh: ", floatA); })
.catch(function(e) {
console.log(e.message); })
.then(close);
}
This is NodeJS and javascript version, which works and Arduino does not. Complete example can be found here and it works on Raspberry Pi https://github.com/yaacov/node-modbus-serial/blob/master/examples/buffer.js
Examples of writing to a port seem to always use the port number as a constant, eg,
OCR2A = 180;
How do you write to the port when the port is unknown until run time. For example,
int port = (buttonPressed) ? 0x3b : 0x3c;
portWrite( port, 180 );
What I cannot find is the funtion portWrite(). Does something like that exist?
Robert's answer has some imprecise assertions and an incomplete answer.
Writing directly to port registers you can ruin other settings of the port and sometimes cause permanent damage to controller.
Can ruin other settings: true, you have to know what you are doing (for instance what pins are on the port you are manipulating, and know what are the functions you want to keep.
Can cause permanent damage: not really, or better not because of the port manipulation. If you wire a short circuit to ground and then set it as an output to 1, you can damage it whether you are using the port register or the digitalwrite. You have to be careful in both ways.
Now, returning to your problem, the enumeration is one way, but since the PORTB, PORTC, PORTD are just short name for values, you can set a variable and then use it to indirectly access it.
The type for this kind of variable is a volatile pointer to a byte (volatile means that write and read operations cannot be optimized by the compiler, since the value can change even between two operations):
volatile uint8_t *variablePortRegister;
You just have to load it with the address (so with the & symbol) of the register you want to change:
variablePortRegister = &PORTC;
then use the pointer to change the value
PORTC = 0x12;
becomes
(*variablePortRegister) = 0x12;
This is a short example. For it to work, connect a LED with resistor on arduino pin 5 (bit 5 of PORTD). The LED on the board (labeled L) is connected to pin 13 (bit 5 of PORTB).
The sketch will make one of the two leds blink for five times, then switch to the other. Only port manipulation instructions are used, and you can find that the way to read the port is the same as the one to write it.
volatile uint8_t *myportreg;
unsigned long lastTime;
uint8_t counter;
void setup() {
DDRB |= 0x20;
DDRD |= 0x20;
PORTB = 0;
PORTD = 0;
counter = 99; // trigger the register change immediately
}
void loop() {
if (counter >= 10)
{
counter = 0;
if (myportreg == &PORTD)
myportreg = &PORTB;
else
myportreg = &PORTD;
}
if ((millis() - lastTime) > 500)
{
lastTime = millis();
// change bit 5 of register
*myportreg = 0x20 ^ (*myportreg);
counter++;
}
}
EDIT: as Robert pointed out, it's much better to "use" just the pins you need (in this case, bit 5 of port B and D) rather than setting the whole port; this way you minimize the risk of screwing up something else. This edit is already included in the above code, so the code is correct
The port is a bit in one particular register. If you know the register and the position of the port in that particular register you can try this:
register = (1<<port) || register
to set the port to 1 and
register = (1<<port)^-1 && register
to set the port to 0.
Of course, you will need a switch somewhere to determine the register and the bit of the port in the register given the port name.
I'll go right to the point. My arduino reads values from the adc port and send them via serial port(values from 0 to 255). I save them in a byte type vector. After sending an specific signal to arduino, it starts to send to Qt app the data saved in the vector. Everything is working except that the arduino should send 800 values and the app receives less values than that. If I set the serial baud rate to 9600, I get 220 values. If, instead, I set the baud rate to 115200, I get only 20 values. Can you guys help me to fix this? I would like to use 115200 baud rate, because I need a good trasmision speed at this project(Real time linear CCD). I'll leave some code below:
Arduino code:
void sendData(void)
{
int x;
for (x = 0; x < 800; ++x)
{
Serial.print(buffer[x]);
}
}
This is the function that sends the values. I think is enough information, so I summarized it. If you need more code, please let me know.
Qt serial port setting code:
...
// QDialog windows private variables and constants
QSerialPort serial;
QSerialPortInfo serialInfo;
QList<QSerialPortInfo> listaPuertos;
bool estadoPuerto;
bool dataAvailable;
const QSerialPort::BaudRate BAUDRATE = QSerialPort::Baud9600;
const QSerialPort::DataBits DATABITS = QSerialPort::Data8;
const QSerialPort::Parity PARITY = QSerialPort::NoParity;
const QSerialPort::StopBits STOPBITS = QSerialPort::OneStop;
const QSerialPort::FlowControl FLOWCONTROL = QSerialPort::NoFlowControl;
const int pixels = 800;
QVector<double> data;
unsigned int dataIndex;
QByteArray values;
double maximo;
...
// Signal and slot connection.
QObject::connect(&serial, SIGNAL(readyRead()), this,SLOT(fillDataBuffer()));
...
// Method called when there's data available to read at the serial port.
void Ventana::fillDataBuffer()
{
dataIndex++;
data.append(QString::fromStdString(serial.readAll().toStdString()).toDouble());
if(data.at(dataIndex-1) > maximo) maximo = data.at(dataIndex-1);
/* The following qDebug is the one I use to test the recieved values,
* where I check that values. */
qDebug() << data.at(dataIndex-1);
}
Thanks and sorry if it's not so clear, it has been an exhausting day :P
Ok... I see two probelms here:
Arduino side: you send your data in a decimal form (so x = 100 will be sent as 3 characters - 1, 0 and 0. You have no delimiter between your data, so how your receiver will know that it received value 100 not three values 1, 0 and 0? Please see my answer here for further explanation on how to send ADC data from Arduino.
QT side: There is no guarantee on the moment when readyRead() signal will be triggered. It may be immediately after first sample arrives, but it may be raised after there are already couple of samples inside the serial port buffer. If that happens, your method fillDataBuffer() may process string 12303402 instead of four separate strings 123, 0, 340 and 2, because between two buffer reads four samples arrived. The bigger the baudrate, the more samples will arrive between the reads, which is why you observe less values with a bigger baud rate.
Solution for both of your problems is to append some delimiting byte for your data, and split the string in the buffer on that delimiting byte. If you don't want to have maximum data throughput, you can just do
Serial.print(buffer[x]);
Serial.print('\n');
and then, split incoming string on \n character.
Thank you very much! I did what you said about my arduino program and after solving that, I was still not getting the entire amount of data. So the the problem was in Qt. How you perfectly explain, the serial buffer was accumulating the values too fast, so the slot function "fillDataBuffer()" was too slow to process the arriving data. I simplified that function:
void Ventana::fillDataBuffer()
{
dataIndex++;
buffer.append(serial.readAll());
}
After saving all the values in the QByteArray buffer, I process the data separately.
Thanks again man. Your answer was really helpful.
I've been working on a project which requires communication with my laptop and the microchip Pic 16f877a and the communication is not working properly, but When i put this example on Proteus 8 works just fine.
I don't have RS232(serial port) on my laptop, but i had bought TTL module. I use external oscillator 8MHz on the board and baud rate of 9600 bps.
When i connect with my laptop and i send to the TTL module the A symbol nothing hapens and when i send a couple of times A fast i recieve strange symbol like '?' or '#' back.
Here's the code for the Pic:
char x;
void main(){
TRISB = 0x00;
PORTB = 0x00;
UART1_Init(9600);
delay_ms(10);
while(1){
if(UART1_Data_Ready())
{
x = UART1_Read();
if(x == 'A')
{
PORTB = 0xFF;
UART1_Write(13);
UART1_Write_Text("A");
UART1_Write(13);
}
else
{
PORTB = 0x00;
}
}
x= '\0';
}
}
Can someone help me ? What's the problem ?
Two possibilities as far as I can see (assuming UART1_Init(9600); is a correct library function):
You don't have the Rx pin set up as an input; setting TRIS registers to 0 makes all the pins on that port outputs.
You are using incorrect parity.
Have you set a breakpoint at line
x = UART1_Read();
To see what you actually get in when you send from your terminal program?
Have you looked on youe scope to see what is actually coming in on the Rx pin?
delay_ms(10); is completely unnecessary.
give
SPBRG = 139
Refer this link to set the respective Baud Rate Generator
I try to send the data from pc to the pic microcontroller. I am a beginner in PIC.
I send the data from hyperterminal and the data will display in the led in port B of PIC.
I used 10Mhz clock and the connection in 9600 baudrate.
here my uart.h program:
char UART_Init(const long int baudrate)
{
unsigned int x;
x = (_XTAL_FREQ - baudrate*64)/(baudrate*64);
if(x>255)
{
x = (_XTAL_FREQ - baudrate*16)/(baudrate*16);
BRGH = 1;
}
if(x<256)
{
SPBRG = x;
SYNC = 0;
SPEN = 1;
TRISC7 = 1;
TRISC6 = 1;
CREN = 1;
TXEN = 1;
return 1;
}
return 0;
}
char UART_TX_Empty()
{
return TRMT;
}
char UART_Data_Ready()
{
return RCIF;
}
char UART_Read()
{
while(!RCIF);
return RCREG;
}
void UART_Read_Text(char *Output, unsigned int length)
{
int i;
for(int i=0;i<length;i++)
Output[i] = UART_Read();
}
void UART_Write(char data)
{
while(!TRMT);
TXREG = data;
}
void UART_Write_Text(char *text)
{
int i;
for(i=0;text[i]!='\0';i++)
UART_Write(text[i]);
}
and this is my main program:
#include<htc.h>
#include<pic.h>
#define _XTAL_FREQ 10000000 //Clock Frequency
#include "uart.h"
void main()
{
TRISB = 0x00; //PORTB as Output
UART_Init(9600);
do
{
if(UART_Data_Ready())
PORTB = UART_Read();
__delay_ms(1000);
}while(1);
}
in hyperteminal I send data say 10010010 but the led in port B do not respond, are there any error in my program?
You have several steps: initialize UART, initialize LEDs, communicate over UART and setup your PC's UART. Which components have you successfully written and tested? You say you're a beginner, so what is the smallest functional program you have successfully executed on a PIC? I've been working with microcontrollers for years, but I still schedule about a whole day to get a single LED to turn on because it could be a software problem, a hardware problem, a voltage problem, an oscillator problem, a PCB problem or a compiler problem.
Here are the steps I take for microchip bring up:
Go over the oscillator section, the configuration bits section, the watchdog section and the pinout section (looking for VDD and VSS) in the datasheet. These are some of the hardest parts to get right. (A gotcha about the oscillator: just because you can program a chip, doesn't mean the oscillator is working because the programmer provides it's own clock.)
Write the bare-minimum code to turn on a single LED.
Write the bare-minimum code to make the LED blink (just use a for-loop delay for now, timers come later)
Write UART initialization code and transmit a single character, I use captial U because it's pretty in binary. TXREG = 'U';
Connect the UART to a PC and see if the hyperterminal sees the U. If it doesn't, I connect an oscilscope to the lines to make sure that the PIC is transmitting, that the PC transmits when I type characters and that the timing of the edges matches.
Within the PIC code, have the UART echo characters from the terminal. (TXREG = RXREG;), and then type on the hyperterminal and make sure the characters are echoed back.
One more note:
Do not have the PIC perform the SPBRG calculation. PIC16 are 8-bit processors and 10000000 requires 32-bits to store. There might be hiccups with the integer divison. It might not have a bug in it, but there's no need to have the PIC calculate it each time. Calculate it before-hand and hard-code the value.