I'm working on a personal home automation project.
On the server side, I have an Arduino Pro Mini with:
a 433 MHz TX module on pin 2
a 433 MHz RX module on pin 3
a DHT22 probe on pin 4 (with 10k pull-up)
a DHT22 probe on pin 5 (with 10k pull-up)
I have two absolutely identical of these modules; one will be the radio relay (and DHT "server") and the other a secondary DHT "server".
When it is linked to my laptop (Debian Wheezy) through an FTDI cable, it can read both local probes and switch my wall plugs on/off thanks to a C program I wrote. I'd like to use it from a Raspberry Pi. But on the Raspberry Pi (with the same FTDI cable on USB), it executes the first command I send and then hangs my terminal, forcing me to use CTRL+C.
Here is the sketch on the Arduino side (header) :
/**
* probe.h
*
* #author David Mézière <...>
*/
/**
* DHT probe result
*
*/
struct Probe {
float temperature;
float humidity;
};
Main file :
/**
* probe.ino
*
* #author David Mézière <...>
*/
#include "probe.h"
/**
* Uses DHT sensor library, from Adafruit.
* #see https://github.com/adafruit/DHT-sensor-library
*/
#include <DHT.h>
/**
* Uses RC Switch library, from sui77.
* #see https://github.com/sui77/rc-switch
*/
#include <RCSwitch.h>
// Pinout definitions
#define TX 2 // 433 MHz transmitter pin number
#define RX 3 // 433 MHz receiver pin number
#define PROBE1 4 // First DHT22 probe pin number
#define PROBE2 5 // Second DHT22 probe pin number
#define LED 13 // On-board status LED pin number
RCSwitch radio = RCSwitch();
// DHT probes definition
DHT dht1(PROBE1, DHT22);
DHT dht2(PROBE2, DHT22);
// Incomming command buffer
byte cmd[9];
/**
* Setup
*
* #return void
*/
void setup()
{
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
Serial.begin(9600);
Serial.setTimeout(1000); // doesn't fix the problem
// Attach receiver to interrupt 1, meaning pin 3
radio.enableReceive(1);
radio.enableTransmit(TX);
dht1.begin();
dht2.begin();
// Debug: Internal LED will blink 3 times rapidly to show when a reboot occurs.
for (int i = 0; i < 3; i++) {
digitalWrite(LED, HIGH);
delay(250);
digitalWrite(LED, LOW);
delay(250);
}
}
/**
* Loop
*
* #return void
*/
void loop()
{
if (Serial.available() == 9 && readCommand()) {
// Lights-up internal LED to show when a command has been executed
digitalWrite(LED, HIGH);
delay(1000);
digitalWrite(LED, LOW);
}
}
/**
* Query probe
*
* Query provided [dht] probe until [retry] times for both temperature and humidity.
*
* #param DHT dht Pointer to DHT object
* #param int retry Number of tries
* #return Probe Probe result (float temperature in °C, float humidity in %)
*/
Probe queryProbe(DHT* dht, int retry)
{
Probe probe;
// Query DHT22 probe for temperature, a maximum of [retry] times.
for (int t = 0; t < retry; t++) {
probe.temperature = dht->readTemperature(false);
if (!isnan(probe.temperature)) {
break;
}
delay(50);
}
// Query DHT22 probe for humidity, a maximum of [retry] times.
for (int h = 0; h < retry; h++) {
probe.humidity = dht->readHumidity();
if (!isnan(probe.humidity)) {
break;
}
delay(50);
}
return probe;
}
/**
* Read command
*
* If serial buffer contains 2 bytes, move them to a local buffer and return true. else return false.
*
* #return boolean
*/
boolean readCommand()
{
// Reads the current buffer
Serial.readBytes(cmd, 9);
// Calculates the check sum of payload
int sum = cmd[2] ^ cmd[3] ^ cmd[4] ^ cmd[5] ^ cmd[6] ^ cmd[7];
// Checking header and checksum a header of 0xBA 0xB1 means DHT query
if (cmd[0] == 0xBA && cmd[1] == 0xB1 && cmd[8] == sum) {
unsigned int module = cmd[2];
unsigned int probe = (cmd[4] << 24) + (cmd[5] << 16) + (cmd[6] << 8) + cmd[7];
Probe result;
switch (module) {
case 1:
// Selects the right probe
if (probe == 1) {
result = queryProbe(&dht1, 3);
} else if (probe == 2) {
result = queryProbe(&dht2, 3);
}
// Send status repport to client
Serial.print("1;");
Serial.print(module);
Serial.print(";");
Serial.print(probe);
Serial.print(";");
Serial.print(result.temperature);
Serial.print(";");
Serial.println(result.humidity);
Serial.flush(); // Doesn't fix the problem
break;
}
return true;
// A header of 0xBA 0xB2 means rf wall plugs query
} else if (cmd[0] == 0xBA && cmd[1] == 0xB2 && cmd[8] == sum) {
unsigned int proto = cmd[2];
unsigned int length = cmd[3];
unsigned int value = (cmd[4] << 24) + (cmd[5] << 16) + (cmd[6] << 8) + cmd[7];
radio.send(value, length);
// Send status repport to client
Serial.print("2;");
Serial.print(proto);
Serial.print(";");
Serial.print(length);
Serial.print(";");
Serial.print(value);
Serial.print(";");
Serial.println("OK");
Serial.flush(); // Doesn't fix the problem
return true;
} else {
Serial.println("KO");
Serial.flush(); // Doesn't fix the problem
return false;
}
}
And on the client side :
/**
* probe.c
*
* #author David Mézière <...>
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <getopt.h>
const char* device;
static int module = 0; // uint_8 ?
static int probe = 0; // uint_8 ?
const char* proto;
static int length = 0; // uint_8 ?
static int value = 0; // uint_32 ?
static int verbose = 0; // uint_8 ?
void help()
{
printf("usage:\n");
printf("\n");
printf("probe [options] [arguments]\n");
printf("\n");
printf("options:\n");
printf(" -h|--help: Displays this help and exit\n");
printf(" -v|--verbose: Be more verbose\n");
printf("\n");
printf("arguments:\n");
printf(" -d|--device: string Serial device to use (ex: /dev/ttyUSB0)\n");
printf(" -m|--module: integer DHT22 module to query\n");
printf(" -p|--probe: integer DHT22 probe to query\n");
printf(" -r|--proto: string Radio / IR protocol\n");
printf(" -l|--length: integer Radio / IR value length in bits\n");
printf(" -a|--value: integer Radio / IR value\n");
printf("\n");
printf("examples:\n");
printf(" probe --device /dev/ttyUSB0 --module 1 --probe 1 : Will query first DHT22 probe of first module\n");
printf(" probe --proto radio1 --length 12 --value 5393 : Will send value 5393 on 12 bits over the air using protocol 1\n");
printf(" probe --proto ir11 --length 64 --value 3772793023 : Will send value 3772793023 on 64 bits by infra red using protocol 11\n");
}
void parseArgs(int argc, char **argv)
{
int c;
while (1) {
static struct option long_options[] = {
{"device", required_argument, 0, 'd'},
{"help", no_argument, 0, 'h'},
{"module", required_argument, 0, 'm'},
{"probe", required_argument, 0, 'p'},
{"proto", required_argument, 0, 'r'},
{"length", required_argument, 0, 'l'},
{"value", required_argument, 0, 'a'},
{"verbose", no_argument, 0, 'v'},
{0, 0, 0, 0}
};
/* getopt_long stores the option index here. */
int option_index = 0;
c = getopt_long(argc, argv, "d:hm:p:v", long_options, &option_index);
/* Detect the end of the options. */
if (c == -1) {
break;
}
switch (c) {
case 0:
/* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0) {
break;
}
printf("option %s", long_options[option_index].name);
if (optarg) {
printf (" with arg %s", optarg);
}
printf("\n");
break;
case 'd':
device = optarg;
break;
case 'h':
help();
exit(0);
break;
case 'm':
module = atoi(optarg);
break;
case 'p':
probe = atoi(optarg);
break;
case 'r':
proto = optarg;
break;
case 'l':
length = atoi(optarg);
break;
case 'a':
value = atoi(optarg);
break;
case 'v':
verbose = 1;
break;
case '?':
/* getopt_long already printed an error message. */
break;
default:
abort();
}
}
/* Print any remaining command line arguments (not options). */
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc) {
printf("%s ", argv[optind++]);
}
putchar('\n');
}
if (&device[0] == '\0') {
fprintf(stderr, "--device is mandatory\n");
exit(1);
} else if (verbose) {
printf("Device: %s\n", device);
}
if (verbose) {
printf("Querying probe %i of module %i.\n", probe, module);
}
}
void initSerial(int fd)
{
struct termios toptions;
/* get current serial port settings */
tcgetattr(fd, &toptions);
/* set 9600 baud both ways */
cfsetispeed(&toptions, B9600);
cfsetospeed(&toptions, B9600);
/* 8 bits, no parity, no stop bits */
toptions.c_cflag &= ~PARENB;
toptions.c_cflag &= ~CSTOPB;
toptions.c_cflag &= ~CSIZE;
toptions.c_cflag |= CS8;
/* Canonical mode */
toptions.c_lflag |= ICANON;
/* commit the serial port settings */
tcsetattr(fd, TCSANOW, &toptions);
}
int main(int argc, char **argv)
{
// Parses command line arguments
parseArgs(argc, argv);
int fd, n, i;
char buf[64] = "temp text";
/* open serial port */
fd = open(device, O_RDWR | O_NOCTTY);
if (verbose) {
printf("Device %s opened as %i\n", device, fd);
}
/*
* Note: Most Arduinos models will reboot upon connection, and they need
* some time for it. I use a pro/mini that doesn't, so i commented it out.
*/
// usleep(3500000);
// Sets the serial port settings (9600 bps, 8 bits, no parity, no stop bits)
initSerial(fd);
/**
* 72 bits
* | Header | Param 1 | Param 2 | Param 3 | sum |
* | 16 b | 8 b | 8 b | 32 b | 8 b |
* Cas 1 : Requête DHT | 0xba 0xb1 | module | 0x00 | sonde | sum |
* Cas 2 : Requête radio | 0xba 0xb2 | proto | length | value | sum |
* Cas 3 : Requête IR | 0xba 0xb3 | proto | length | value | sum |
*/
unsigned char oBuf[9];
// printf("%s\n", proto);
// printf("%i\n", length);
if (module > 0 && probe > 0) {
if (verbose) {
printf("DHT mode\n");
}
oBuf[0] = 0xBA;
oBuf[1] = 0xB1; // DHT query
oBuf[2] = module;
oBuf[3] = 0x00;
oBuf[4] = (probe >> 24) & 0xFF;
oBuf[5] = (probe >> 16) & 0xFF;
oBuf[6] = (probe >> 8) & 0xFF;
oBuf[7] = probe & 0xFF;
oBuf[8] = oBuf[2];
oBuf[9] = '\n';
// Calculates the XOR sum
for (i = 3; i < 8; i++) {
oBuf[8] ^= oBuf[i];
}
// sprintf(oBuff, "%c%c%c%c%c%c", 0xba, 0xb1, module, 0x00, probe, sum);
} else if (strcmp((const char*)proto, "radio1") == 0 && length > 0) {
if (verbose) {
printf("Radio mode\n");
}
oBuf[0] = 0xBA;
oBuf[1] = 0xB2; // Radio query
oBuf[2] = 0x01; // Protocol 1
oBuf[3] = length;
oBuf[4] = (value >> 24) & 0xFF;
oBuf[5] = (value >> 16) & 0xFF;
oBuf[6] = (value >> 8) & 0xFF;
oBuf[7] = value & 0xFF;
oBuf[8] = oBuf[2];
oBuf[9] = '\n';
// Calculates the XOR sum
for (i = 3; i < 8; i++) {
oBuf[8] ^= oBuf[i];
}
} else {
if (verbose) {
printf("Unknown mode\n");
}
}
/* Send the buffer */
write(fd, oBuf, 9);
/* Receive string from Arduino */
n = read(fd, buf, 64);
/* insert terminating zero in the string */
buf[n] = 0;
if (verbose) {
printf("%i bytes read, buffer contains: %s\n", n, buf);
} else {
printf("%s", buf);
}
return 0;
}
I compile it using just gcc probe.c -o probe.
On Debian, I can use the system as much as I want, it works:
dmeziere#portable2-wlan:~/dev/probe$ gcc probe.c -o probe
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 1
1;1;1;23.60;43.10
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 2
1;1;2;23.60;38.50
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --proto radio1 --length 24 --value 5396
2;1;24;5396;OK
dmeziere#portable2-wlan:~/dev/probe$ ./probe --device /dev/ttyUSB0 --proto radio1 --length 24 --value 5393
2;1;24;5393;OK
On Raspbian, the first call works, but the second hangs my terminal and I have to do CTRL+C:
dmeziere#raspberrypi:~/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 1
1;1;1;23.90;39.00
dmeziere#raspberrypi:~/probe$ ./probe --device /dev/ttyUSB0 --module 1 --probe 2
^C
I found it !
It seems like on Raspbian, the communications were terminated by a NULL character. But not on Debian. And this NULL character was polluting my calculations of incomming buffer length. So i ended up by eventually suppress it on the Arduino side :
boolean readCommand()
{
// Reads the current buffer
Serial.readBytes(cmd, 9);
// If sender sends a null character, remove it.
int test = Serial.peek();
if (test == 0x00) {
test = Serial.read();
}
// ...
}
Related
I'm trying to call a C function from Fortran, using the iso_c_binding interoperability. However, I am getting a SegFault error when trying to use print and write statements. Without the print and write statements the code works fine, but I need these statements to create an output file with the simulation data. Does anyone know how to solve this problem?
Note: I am using Ubuntu 20.04, GFortran, and GCC to compile the respective source codes.
gcc -c subroutine_in_c.c
gfortran -o exec main.f90 subroutine_in_c.o -lwiringPi
main.f90:
PROGRAM main
USE, INTRINSIC:: iso_c_binding, ONLY: C_FLOAT
IMPLICIT NONE
REAL(KIND = 4) :: leitura_sensor = 0.0
INTERFACE
SUBROUTINE ler_sensores(s1) BIND(C)
USE, INTRINSIC :: iso_c_binding, ONLY: C_FLOAT
IMPLICIT NONE
REAL(KIND=C_FLOAT) :: s1
END SUBROUTINE ler_sensores
END INTERFACE
!print*, 'Call subroutine in C language'
call ler_sensores(leitura_sensor)
!print*, 'Return to main.f90'
OPEN(UNIT=1, FILE='output.txt', STATUS='unknown')
WRITE(1,*) leitura_sensor
CLOSE(UNIT=1)
END PROGRAM main
subroutine_in_c.c:
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <wiringPiSPI.h>
#include <wiringPiI2C.h>
#define LCDADDR 0x27 //IIC LCD address
#define BLEN 1 //1--open backlight,0--close backlight
#define CHAN_CONFIG_SINGLE 8 //setup channel 0 as Single-ended input
#define SPICHANNEL 0 //MCP3008 connect to SPI0
#define ANALOGCHANNEL 0 //Potentiometer connect MCP3008 analog channel 0
#define ANALOGCHANNEL2 1
static int spifd;
static int i2cfd;
void
spiSetup (int spiChannel)
{
if ((spifd = wiringPiSPISetup (spiChannel, 10000)) < 0)
{
fprintf (stderr, "Can't open the SPI bus: %s\n", strerror (errno)) ;
exit (EXIT_FAILURE) ;
}
}
int
myAnalogRead(int spiChannel,int channelConfig,int analogChannel)
{
if (analogChannel<0 || analogChannel>7)
return -1;
unsigned char buffer[3] = {1}; // start bit
buffer[1] = (channelConfig+analogChannel) << 4;
wiringPiSPIDataRW(spiChannel, buffer, 3);
return ( (buffer[1] & 3 ) << 8 ) + buffer[2]; // get last 10 bits
}
//write a word to lcd
void
write_word(int data)
{
int temp = data;
if ( BLEN == 1 )
temp |= 0x08;
else
temp &= 0xF7;
wiringPiI2CWrite(i2cfd, temp);
}
//send command to lcd
void
send_command(int comm)
{
int buf;
// Send bit7-4 firstly
buf = comm & 0xF0;
buf |= 0x04; // RS = 0, RW = 0, EN = 1
write_word(buf);
delay(2);
buf &= 0xFB; // Make EN = 0
write_word(buf);
// Send bit3-0 secondly
buf = (comm & 0x0F) << 4;
buf |= 0x04; // RS = 0, RW = 0, EN = 1
write_word(buf);
delay(2);
buf &= 0xFB; // Make EN = 0
write_word(buf);
}
//send data to lcd
void
send_data(int data)
{
int buf;
// Send bit7-4 firstly
buf = data & 0xF0;
buf |= 0x05; // RS = 1, RW = 0, EN = 1
write_word(buf);
delay(2);
buf &= 0xFB; // Make EN = 0
write_word(buf);
// Send bit3-0 secondly
buf = (data & 0x0F) << 4;
buf |= 0x05; // RS = 1, RW = 0, EN = 1
write_word(buf);
delay(2);
buf &= 0xFB; // Make EN = 0
write_word(buf);
}
//initialize the lcd
void
init()
{
send_command(0x33); // Must initialize to 8-line mode at first
delay(5);
send_command(0x32); // Then initialize to 4-line mode
delay(5);
send_command(0x28); // 2 Lines & 5*7 dots
delay(5);
send_command(0x0C); // Enable display without cursor
delay(5);
send_command(0x01); // Clear Screen
wiringPiI2CWrite(i2cfd, 0x08);
}
//clear screen
void
clear()
{
send_command(0x01); //clear Screen
}
//Print the message on the lcd
void
write(int x, int y, char data[])
{
int addr, i;
int tmp;
if (x < 0) x = 0;
if (x > 15) x = 15;
if (y < 0) y = 0;
if (y > 1) y = 1;
// Move cursor
addr = 0x80 + 0x40 * y + x;
send_command(addr);
tmp = strlen(data);
for (i = 0; i < tmp; i++) {
send_data(data[i]);
}
}
void
ler_sensores(float *s1)
{
int adc;
int adc2;
int i;
float voltage;
float voltage2;
char buf[5];
if (wiringPiSetup() < 0)
{
fprintf(stderr,"Can't init wiringPi: %s\n",strerror(errno));
exit(EXIT_FAILURE);
}
spiSetup(SPICHANNEL);//init spi
i2cfd = wiringPiI2CSetup(LCDADDR); //init i2c
init(); //init LCD
clear(); //clear screen
for (i = 0; i <25; i++) {
adc = myAnalogRead(SPICHANNEL,CHAN_CONFIG_SINGLE,ANALOGCHANNEL);
adc2 = myAnalogRead(SPICHANNEL, CHAN_CONFIG_SINGLE, ANALOGCHANNEL2);
voltage = adc/1024.*20.0;
write(0,0,"Ch Linear:");
sprintf(buf,"%2.2f",voltage);//float change to string
write(10,0,buf);//print voltage on lcd
write(15,0,"V");//print unit
write(0,1,"Ch Logarit:");
voltage2 = adc2/1024.*20.0;
sprintf(buf,"%2.2f",voltage2);
write(11,1, buf);
write(16,1,"V");
delay(1000);
}
*s1 = voltage;
}
Thank you in advance to everyone who helps.
This question probably deserves an answer even if the reason for the problem is the obscure one, identified by Craig Estay.
Gfortran's runtime library, called when using the print and write statements, contains calls to write() and having another C function called write will cause the gfortran runtime to call a wrong function.
It can easily be tested in a simple program like this:
testwrite.c:
#include "stdio.h"
void write(){
puts("my C write");
}
testwrite.f90:
print *,"test print"
write(*,*) "test write"
end
When using gfortran testwrite.c testwrite.f90, the output is:
my C write
my C write
my C write
my C write
The same output appears when using icc testwrite.c -c -o c.o and ifort c.o testwrite.f90.
I've attached an image showing my oscilloscope readout which is from the code below. Context: I have a Pi and a PIC which need to communicate through UART connection. I've implemented my own flow control which can be seen in the image attached [RTS = Yellow Trace, CTS = Blue Trace, Rx = Green Trace]. The code runs through and is caught in the final switch case statement which turns on an LED. But when i debug the code, no values (well the only value which is read is zero) are read in. At first i thought that i'd configured my PIC clock wrong (which is used to derive the baud rate), but i don't think this is the case. Second i through the FIFO buffer was full of zeros only and considering that i'm sending only four packets of information to the PIC, and my FIFO is 4 registers deep that this was the reason why non of the information was appearing. So i executed a code which removes the dummy bytes but this did not work.
All that is received:
0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0> etc
I got the right settings selected: baud rate: 9600 data bits: 8 parity: none stop bits: 1
If anyone is willing to spend some time looking at my code, can you see any obvious errors?
https://i.stack.imgur.com/aQoAL.jpg
Minimum Reproducible Example
# include <xc.h>
# include <math.h>
# include <stdio.h>
# include <stdio.h>
//Configuration Bits
#pragma config FNOSC = FRCPLL // Internal Fast RC Oscillator (8MHz)
#pragma config FPLLIDIV = DIV_2 // Divide FRC before PLL (Now 4MHz)
#pragma config FPLLMUL = MUL_20 // PLL Multiply (Now 80MHz)
#pragma config FPLLODIV = DIV_2 // Divide After PLL (Now 40MHz)
#pragma config FPBDIV = DIV_1 // Pheripheral Bus Clock (At 40KHz)
#pragma config FWDTEN = OFF // Watchdog Timer Disabled
#pragma config ICESEL = ICS_PGx2 // ICE/ICD Comm Channel Select
#pragma config JTAGEN = OFF // Disable JTAG
#pragma config FSOSCEN = OFF // Disable Secondary Oscillator
//*****************************UART Functions***********************************
void UART_Config (void) // Baude Rate of 9600, 8-Bit Data , 1 Stop Bit
{
U1MODEbits.BRGH = 0;
U1BRG = 259; //U1BRG = (40M/ (16 * 9.6k))) - 1
U1MODEbits.SIDL = 0; // Continue operation in SLEEP mode
U1MODEbits.IREN = 0; // IrDA is disabled
U1MODEbits.RTSMD = 0; // U1RTS pin is in Flow Control mode
U1MODEbits.UEN = 0b00; // U1TX, U1RX are enabled
U1MODEbits.WAKE = 1; // Wake-up enabled
U1MODEbits.LPBACK = 0; // Loopback mode is disabled
U1MODEbits.RXINV = 0; // U1RX IDLE state is '1'
U1MODEbits.PDSEL = 0b00; // 8-bit data, no parity
U1MODEbits.STSEL = 0; // 1 stop bit
U1STAbits.UTXINV = 0; // U1TX IDLE state is '1'
U1MODEbits.ON = 1; // UART1 is enabled
U1STAbits.URXEN = 1; // UART1 receiver is enabled
U1STAbits.UTXEN = 1; // UART1 transmitter is enabled
}
void Send_UART_Data(unsigned int c) // PIC Sending Data for Pi to Read
{
U1STAbits.UTXEN = 1; // Make sure transmitter is enabled
// while(CTS) // Optional CTS (Clear to Send) use
while(U1STAbits.UTXBF); // Wait while buffer is full
U1TXREG = c; // Transmit character
}
int Read_UART_Data (void) // PIC Reading Sent Data from Pi
{
int c;
while(!U1STAbits.URXDA) // Wait for information to be received
c = (int)U1RXREG; // Convert Character to Value
return c;
}
ADC_To_UART (unsigned int ADC)
{
unsigned int temp_A = 0x00;
unsigned int temp_B = 0x00;
// Splitting a 10 Bit Word Into 2 Bytes [aa aaaa aabb]
// Start Bit = 1 , Stop Bit = 0
// UART Transmission Pattern [1 aaaa aaaa 0 0000 00 bb]
temp_A = ADC >> 2; // MSB(8 Bits) ~ ADC[9:2] [aaaa aaaa]
temp_B = ADC & 0x003; // LSB(2 Bits) ~ ADC[1:0] [0000 00bb]
Send_UART_Data(temp_A);
Send_UART_Data(temp_B);
}
[enter image description here][1]
//*********************Enumerated Variable Declaration**************************
//Program Flow Control
enum Comm_State {Phase1A, Phase1B, Phase1C, Phase1D, Phase1E, Phase2A, Phase2B, Phase2C, Phase2D, Phase2E, Phase2F, Phase2G};
//******************************************************************************
//********************************MAIN******************************************
int main( )
{
//***************************Configuration**********************************
// I/O Definitions
#define UART_TRIS_RX TRISBbits.TRISB13 // UART RX - Reciever Pin (PPS)
#define UART_TRIS_TX TRISBbits.TRISB15 // UART TX - Transmission Pin (PPS)
#define UART_TRIS_CTS_PIC TRISAbits.TRISA4 // UART CTS_1 - Clear to Send - Output [CTS PIC]
#define UART_TRIS_RTS_PIC TRISBbits.TRISB4 // UART RTS_1 - Ready to Send - Output [RTS PIC]
#define UART_TRIS_CTS_PI TRISAbits.TRISA3 // UART CTS_2 - Clear to Send - Input [CTS PI]
#define UART_TRIS_RTS_PI TRISAbits.TRISA2 // UART_RTS_2 - Ready to Send - Input [RTS PI]
#define SPI_TRIS_SCK TRISBbits.TRISB14 // SPI SCK - Serial Clock Pin (PPS?)
#define SPI_TRIS_SDO TRISBbits.TRISB6 // SPI SDO - Serial Data Out Pin (PPS?)
#define SPI_TRIS_CS_1 TRISBbits.TRISB8 // SPI CS1 - DAC 2 Chip Select Pin (PPS?)
#define SPI_TRIS_CS_2 TRISBbits.TRISB7 // SPI CS2 - DAC 1 Chip Select Pin (PPS?)
#define AN4_TRIS TRISBbits.TRISB2 // Analogue Read 3
#define AN3_TRIS TRISBbits.TRISB1 // Analogue Read 2
#define AN2_TRIS TRISBbits.TRISB0 // Analogue Read 1
#define V_REF_TRIS_Plus TRISAbits.TRISA0 // Analogue V_REF(+) (Forms VRange)
#define V_REF_TRIS_Minus TRISAbits.TRISA1 // Analogue V_REF(-) (Forms VRange)
#define Reg_Enable_TRIS_D TRISBbits.TRISB9 // Regulator Digital Control (Output)
#define Reg_Enable_TRIS_M TRISBbits.TRISB12 // Regulator Button (Input)
// Port Input/Output Configuration [TRISB]
TRISB = 0x1004; // All of PortB set as Outputs Except for RB12 (Reg Enable) and RB2 (Input -> Analogue Input (Voltage)) (Port B) = (0000 ... 0100)
TRISA = 0x0003; // Set up A0 [Pin 2] and A1 [Pin 3] as V_REF(+) and V_REF(-) Respectively (Port B) = (0000 ... 0011)
UART_TRIS_RX = 1; // UART Receiver ~ Input
UART_TRIS_TX = 0; // UART Transmission ~ Output
UART_TRIS_CTS_PIC = 0; // UART "CTS_PIC" ~ Output
UART_TRIS_RTS_PIC = 0; // UART "RTS_PIC" ~ Output
UART_TRIS_CTS_PI = 1; // UART "CTS_PI" ~ Input
UART_TRIS_RTS_PI = 1; // UART "RTS_PI" ~ Input
SPI_TRIS_SCK = 0; // SPI Clock ~ Output
SPI_TRIS_SDO = 0; // SPI Data Output ~ Output
SPI_TRIS_CS_1 = 0; // SPI Chip Select 1 ~ Output
SPI_TRIS_CS_2 = 0; // SPI Chip Select 2 ~ Output
AN4_TRIS = 1; // Analogue Read In ~ Input
AN3_TRIS = 1; // Analogue Read In ~ Input
AN2_TRIS = 1; // Analogue Read In ~ Input
V_REF_TRIS_Plus = 1; // V_Ref(+) ~ Input
V_REF_TRIS_Minus = 1; // V_Ref(-) Differential Measurements ~ Input
Reg_Enable_TRIS_D = 0; // Regulator Digital Control (Output)
Reg_Enable_TRIS_M = 1; // Regulator Switch Control (Input)
// Peripheral Pin Select Configurations
U1RXR = 0x0011; // UART PPS Mapping
RPB15R = 0x0001; // UART PPS Mapping
// Analogue Pin Configurations
ANSELB = 0x0028; // RB0 RB1 RB2 = AN2 AN3 AN4 [0001 1100]
ANSELA = 0x0000; // Set all Analogue Inputs of Port A Off
//**************Sub-System Configurations*********************************//
// UART Control Configure
UART_Config(); //UART Control Configure
#define PIC_CTS LATAbits.LATA4 // Output Set Definition [1]
#define PIC_RTS LATBbits.LATB4 // Output Set Definition [2]
#define PI_CTS PORTAbits.RA3 // Input Read Definition [2]
#define PI_RTS PORTAbits.RA2 // Input Read Definition [1]
// Analogue Control Configure
ADC_Config(); // Configure ADC
AD1CON1SET = 0x8000; // Enable ADC
//***************Variable Declarations************************************//
enum Comm_State Communication_State = Phase1A; //Controller Variable
unsigned int temp1 = 0;
unsigned int Comms_Flag_1 = 0;
unsigned int ConFlag = 1;
unsigned int i = 1;
unsigned int UART_ADC_CV_1 = 0;
unsigned int UART_ADC_CV_2 = 0;
unsigned int ADC_CV = 0;
unsigned int UART_ADC_CC_1 = 0;
unsigned int UART_ADC_CC_2 = 0;
unsigned int ADC_CC = 0;
unsigned int DAC_CV = 0;
float I_CC = 0;
float V_CV = 0;
//***************Program Flow - Switch State Controlled*******************//
while(1)
{
switch (Communication_State)
{
case Phase1A: // Check For Pi Ready to Send CV ADC Value
//PIC_CTS = 0;
//Pic_Refresh();
PIC_RTS = 0;
PIC_CTS = 1;
if (PI_RTS == 1)
{
PIC_CTS = 0;
Communication_State = Phase1B;
}
break;
case Phase1B: // Receive CV ~ 12 Bit ADC Value [Two Data Packets with 0.01 Second Delay]
ConFlag = 1;
i = 1;
while (ConFlag == 1)
{
if (PI_RTS == 1 && i == 1)
{
UART_ADC_CV_1 = Read_UART_Data(); //Data Packet 1 Returned - MSB(Bit 15) to Bit 8
i++;
}
else if (PI_RTS == 1 && i == 2)
{
UART_ADC_CV_2 = Read_UART_Data(); //Data Packet 2 Returned - Bit (7)) to LSB(Bit 0)
}
else
{
ConFlag = 0;
}
}
Communication_State = Phase1C;
break;
case Phase1C: // Check for CC Value
delay(); //Ensure that Pi_RTS has gone low after sending last Transmission (Prevents Code from Running Away)
PIC_CTS = 1;
if (PI_RTS == 1)
{
PIC_CTS = 0;
Communication_State = Phase1D;
}
break;
case Phase1D: // Receive CC Value [Two Data Packets with 0.01 Second Delay]
ConFlag = 1;
i = 1;
while (ConFlag == 1)
{
if (PI_RTS == 1 && i == 1)
{
UART_ADC_CC_1 = Read_UART_Data(); //Data Packet 1 Returned - MSB(Bit 15) to Bit 8
i++;
}
else if (PI_RTS == 1 && i == 2)
{
UART_ADC_CC_2 = Read_UART_Data(); //Data Packet 2 Returned - Bit (7)) to LSB(Bit 0)
}
else
{
ConFlag = 0;
}
}
Communication_State = Phase1E;
break;
case Phase1E: // Calculations
// CV Calculations
temp1 = UART_ADC_CV_1 << 8;
ADC_CV = temp1 + UART_ADC_CV_2;
V_CV = ADC_CV * (4.096/4096);
DAC_CV = ADC_CV | 4096;
Comms_Flag_1 = SPI_Transfer(DAC_CV ,1); // Data Transmitted to DAC 1, Upon Transmission LED Turns Green (No Acknowledgement)
// CC Calculations
temp1 = UART_ADC_CC_1 << 8;
ADC_CC = temp1 + UART_ADC_CC_2;
I_CC = ADC_CC * (4.096/4096);
Communication_State = Phase2A;
break;
case Phase2A:
while(1)
{
LATBbits.LATB5 = 1;
}
break;
}
}
return 1;
}
In Read_UART_Data, you have:
while(!U1STAbits.URXDA)
c = (int)U1RXREG;
I think you're missing a semicolon because this is actually:
while (!U1STAbits.URXDA)
c = (int) U1RXREG;
This means that c is set only when the UART receiver is not ready.
What I think you meant is:
while (!U1STAbits.URXDA);
c = (int) U1RXREG;
I'm trying to read information from an MPU6050 sensor using the SAM4S-EK2 dev board, with an ATSAM4SD32C microcontroler, showing the data in the on-board LCD display. However, when I try to read the data, the received value that shows up in the LCD is always the same.
What am I doing wrong?
I'm using Atmel Studio 7 with ASF version 3.32.0
Here is my current code:
#include <asf.h>
#define TWI_CLK 200000
#define ADDRESS 0x68
#define READ 0x3b
#define ILI93XX_LCD_CS 1
twi_options_t opt;
struct ili93xx_opt_t g_ili93xx_display_opt;
void configure_lcd()
{
/** Enable peripheral clock */
pmc_enable_periph_clk(ID_SMC);
/** Configure SMC interface for Lcd */
smc_set_setup_timing(SMC, ILI93XX_LCD_CS, SMC_SETUP_NWE_SETUP(2)
| SMC_SETUP_NCS_WR_SETUP(2)
| SMC_SETUP_NRD_SETUP(2)
| SMC_SETUP_NCS_RD_SETUP(2));
smc_set_pulse_timing(SMC, ILI93XX_LCD_CS, SMC_PULSE_NWE_PULSE(4)
| SMC_PULSE_NCS_WR_PULSE(4)
| SMC_PULSE_NRD_PULSE(10)
| SMC_PULSE_NCS_RD_PULSE(10));
smc_set_cycle_timing(SMC, ILI93XX_LCD_CS, SMC_CYCLE_NWE_CYCLE(10)
| SMC_CYCLE_NRD_CYCLE(22));
smc_set_mode(SMC, ILI93XX_LCD_CS, SMC_MODE_READ_MODE
| SMC_MODE_WRITE_MODE);
/** Initialize display parameter */
g_ili93xx_display_opt.ul_width = ILI93XX_LCD_WIDTH;
g_ili93xx_display_opt.ul_height = ILI93XX_LCD_HEIGHT;
g_ili93xx_display_opt.foreground_color = COLOR_BLACK;
g_ili93xx_display_opt.background_color = COLOR_WHITE;
/** Switch off backlight */
aat31xx_disable_backlight();
/** Initialize LCD */
ili93xx_init(&g_ili93xx_display_opt);
/** Set backlight level */
aat31xx_set_backlight(AAT31XX_AVG_BACKLIGHT_LEVEL);
ili93xx_set_foreground_color(COLOR_WHITE);
ili93xx_draw_filled_rectangle(0, 0, ILI93XX_LCD_WIDTH,
ILI93XX_LCD_HEIGHT);
/** Turn on LCD */
ili93xx_display_on();
ili93xx_set_cursor_position(0, 0);
}
int main (void)
{
sysclk_init();
board_init();
configure_lcd();
pio_configure(PIOB, PIO_PERIPH_B, (PIO_PB5A_TWCK1 | PIO_PB4A_TWD1), PIO_OPENDRAIN);
pmc_enable_periph_clk(ID_TWI1);
opt.master_clk = sysclk_get_peripheral_hz();
opt.speed = TWI_CLK;
twi_enable_master_mode(TWI1);
twi_master_init(TWI1, &opt);
twi_packet_t packet;
uint8_t answer[20];
answer[0]=0x00;
//pacote.addr[0] = 0x6b;
//pacote.addr_length = 1;
//pacote.buffer = &resposta;
//pacote.chip = ENDERECO_SENSOR;
//pacote.length = 1;
//
//if(twi_master_write(TWI1, &pacote) == TWI_SUCCESS)
//{
//ili93xx_set_foreground_color(COLOR_WHITE);
//ili93xx_draw_filled_rectangle(0, 0, 200, 200);
//ili93xx_set_foreground_color(COLOR_BLACK);
//ili93xx_draw_string(0, 0, "Enviou");
//}
while(1)
{
packet.addr[0] = READ;
packet.addr_length = 1;
packet.buffer = &answer;
packet.chip = ADDRESS;
packet.length = 14;
twi_master_read(TWI1, &packet);
char a[20];
int16_t b;
b = (answer[2] << 8 | answer[3]);
sprintf(a,"%i",b);
ili93xx_set_foreground_color(COLOR_WHITE);
ili93xx_draw_filled_rectangle(95, 175, 240, 200);
ili93xx_set_foreground_color(COLOR_BLACK);
ili93xx_draw_string(100, 180, a);
delay_ms(100);
}
}
I am working with the raspberry pi and atmega 32 to use and learn SPI. it should follow a transition diagram but somewhere in the atmega it goes wrong, I don't know where it is going wrong.
this is the raspberry code
#include <wiringPi.h>
#include <stdio.h>
#include <wiringPiSPI.h>
#define SELECTADC 6
#define READY 8
#define GIVEADC 32
#define NOTREADY 0x10
#define DUMMY 0x55
#define ACK 10
#define IDLE 1
#define POLL 2
#define ADCSTART 3
#define ADCSTATE 4
#define ADCRESULT 5
main() {
int tellerPoll=0;
int teller=0;
int adcStatusTeller=0;
int status=0;
unsigned char data[4];
wiringPiSetup();
int kanaal = 0;
int adc;
int adcHigh=0;
int error=0;
if( wiringPiSPISetup (0, 500000)==-1)
{
printf("Could not initialise SPI\n");
status=0;
return;
} else {
status = IDLE;
printf("succesful initialised\n");
}
for(;;)
{
delay(20);
//wiringPiSPIDataRW(0,data,1);
switch(status){
case 0 :
exit(0);
case IDLE :
teller +=1;
if((teller % 2 == 1)&&1){
data[0] = POLL;
wiringPiSPIDataRW(0,data,1);
status = POLL;
//teller=0;
printf("Poll\n");
}
else if ((teller % 2 == 0)&&1){
status = ADCSTART;
}
break;
case POLL :
data[0] = DUMMY;
wiringPiSPIDataRW(0,data,1);
printf("Poll result: %x\n", data[0]);
if(data[0]==ACK){
status=IDLE;
printf("Poll succesfull\n");
tellerPoll=0;
}
else{
tellerPoll+=1;
if(tellerPoll>20){
status=0;
printf("No device found\n");
tellerPoll=0;
}
}
break;
case ADCSTART :
data[0]=ADCSTART;
wiringPiSPIDataRW(0,data,1);
status = ADCSTATE;
printf("ADCSTART\n");
break;
case ADCSTATE :
// printf("ADCSTATE\n");
data[0]=ADCSTATE;
wiringPiSPIDataRW(0,data,1);
//printf("%x\n",data[0]);
if(data[0]==READY){
status=ADCRESULT;
printf("Ready\n");
break;
}
else if(data[0]==NOTREADY){
printf("NOTREADY\n");
status=ADCSTATE;
adcStatusTeller+=1;
if(adcStatusTeller==100){
status=IDLE;
adcStatusTeller=0;
printf("no ADC result\n");
}
}
else{
adcStatusTeller+=1;
status =ADCSTATE;
printf("Weird result: %x\n", data[0]);
if (adcStatusTeller==100){
status=IDLE;
adcStatusTeller=0;
printf("no Results: %x \n", data[0]);
}
}
break;
case ADCRESULT :
data[0]=GIVEADC;
wiringPiSPIDataRW(0,data,1);
data[0]=DUMMY;
wiringPiSPIDataRW(0,data,1);
adc = data[0];
delay(10);
data[0]=DUMMY;
wiringPiSPIDataRW(0,data,1);
adcHigh=data[0];
//adcHigh &= 0b11000000;
//adcHigh <<=2;
//adc += adcHigh;
printf("ADC %d heeft waarde %x %x \n",kanaal, adcHigh, adc);
status=IDLE;
break;
case SELECTADC :
data[0]=SELECTADC;
wiringPiSPIDataRW(0,data,1);
data[0]=DUMMY;
wiringPiSPIDataRW(0,data,1);
if(data[0]==ACK){
delay(10);
data[0]=kanaal;
wiringPiSPIDataRW(0,data,1);
printf("ADC %s is succesfully selected",kanaal);
status=POLL;
}
else{
printf("There was an error selecting the ADC");
status=SELECTADC;
error+=1;
if(error==20){
status=POLL;
error=0;
printf("No ADC selected");
break;
}
}
break;
default :
printf("default\n");
break;
}
kanaal=0;
}
}
And Atmega32
#include <stdlib.h>
#include <avr/io.h>
void adc_init(void);
void SPI_SlaveInit(void);
unsigned char SPI_SlaveReceive(unsigned char);
void leesADC(char);
#define IDLE 1
#define POLL 2
#define ADCSTART 3
#define ADCSTATE 4
#define SELECTADC 6
#define READY 8
#define ACK 10
#define GIVEADC 32
#define NOTREADY 0x10
#define DUMMY 0x55
void SPI_SlaveInit(void)
{
/* Set MISO output, all others input */
DDRB = (1<<PB6);
/* Enable SPI */
SPCR = (1<<SPE);
}
unsigned char SPI_SlaveReceive(unsigned char data)
{
SPDR = data;
/* Wait for reception complete */
while(!(SPSR & (1<<SPIF) ));
/* Return data register */
return SPDR;
}
//starADC
void leesADC(char kanaal)
{
ADMUX &= 0b11100000;
ADMUX |= kanaal & 7;
ADCSRA |= (1<<ADSC);
}
void adc_init(void)
{
ADMUX=(1<<REFS0)|(1<<ADLAR); //voedings U als referentie, links uitlijnen in de 10bit
ADCSRA=(1<<ADEN); // adc enablen, start conversion, auto trigger enable
}
int main(void)
{
DDRC= 0b11111111;
DDRD= 0b11111111;
SPI_SlaveInit();
adc_init();
int kanaal=0;
leesADC(kanaal);
char stap;
char status;
while(1)
{
switch(stap){
case IDLE :
stap = SPI_SlaveReceive(status);
break;
case POLL :
status = ACK;
stap=IDLE;
PORTD=15;
break;
case ADCSTART :
status = ADCSTART;
leesADC(kanaal);
PORTD=255;
break;
case ADCSTATE :
if ((ADCSRA & (1<<ADIF)) == 0){
status = NOTREADY;
} else{
status = READY;
}
stap=IDLE;
break;
case GIVEADC :
stap= ADCH;
break;
case SELECTADC :
kanaal = SPI_SlaveReceive(DUMMY);
stap=DUMMY;
break;
default : ;
}
}
}
Thanks in advance.
You don't initialize the stap variable, which means its value will be indeterminate. Attempting to use it in the switch statement will lead to undefined behavior.
I suppose you should be initializing it to IDLE:
int stap = IDLE;
How to change the transmission of bytes via the port?
Was: Interrupt.
Need: According to the poll.
plug-in -> http://pastie.org/3994352
Client:
#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include "comm.h" // Connect module
void main(void)
{
char cmd[128];
/* Set the COM port */
printf("Adjustable com-port ...\n");
OpenSerial(COM_1, SER_BAUD_9600, SER_STOP_2 | SER_BITS_8 | SER_PARITY_EVEN);
printf("Submitting a request for a connection ...\n");
WriteSer(0xFF);
while (1)
{
if (kbhit())
{
int c = getche();
if (c == 13) putch(10);
WriteSer(c);
}
if (DataReadyCount())
{
int c = ReadQueue();
if (c == 0xFF) break;
putch(c);
}
}
printf("Ending a connection ...\n");
CloseSerial();
}
I found a sample on the web which may be of value, at least in showcasing the polling vs. interrupt driven approaches. Note that the interrupt method needs calls to setvect, outportb, saving the old interrupt and restoring it, etc.
Don't ask about TSRs next. :)
// http://ragestorm.net
// serial communications example
// interrupt driven/polled method
#include <dos.h>
#include <conio.h>
#include <stdio.h>
// serial port base addresses:
#define COM1 (0x3f8)
#define COM2 (0x2f8)
// stack size for interrupt
#define STACK_SIZE 1024
// serial ports registers:
// receive buffer
#define RBR (0x0)
// transmitter hold
#define THR (0x0)
// interrupt enable
#define IER (0x1)
// interrupt identification
#define IIR (0x2)
// fifo control
#define FCR (0x2)
// line control
#define LCR (0x3)
// modem control
#define MCR (0x4)
// line status
#define LSR (0x5)
// modem status
#define MSR (0x6)
// scratch-pad
#define SPR (0x7)
// divisor lsb byte
#define DIVLSB (0x0)
// divisor msb byte
#define DIVMSB (0x1)
// possible irqs for com ports
int com_irqs[4] = {4, 3, 4, 3};
// the com port addr being used
int used_com_addr = 0;
// the irq being used if interrupt driven
int used_com_irq = 0;
// interrupt driven or polling method?
int intr_used = 0;
// built in stack for interrupt usage
unsigned char recv_stack[STACK_SIZE];
unsigned char* next_char = recv_stack;
// old handler address
void interrupt (*old_handler)(...) = NULL;
void interrupt new_handler(...);
// get com address from bios
unsigned short get_com_addr(int com_no)
{
if ((com_no <= 0) || (com_no >= 5)) return -1;
// bios seg addr
unsigned char* biosaddr = (unsigned char *)0x400;
// set irq according to com number
used_com_irq = com_irqs[com_no - 1];
// retreive addresses bios
return *(unsigned short*)&biosaddr[(com_no - 1) << 1];
}
// detect the uart type of the used com prot addr
// this is mainly to know if fifo is available.
// 0: no uart found, 1: 8250, 2: 16450 or 8250(with spr), 3: 16550, 4: 16550A
int detect_uart_type()
{
char old_data = 0;
// check UART presentation by checking loopback mode
old_data = inportb(used_com_addr + MCR);
outportb(used_com_addr + MCR, 0x10);
if ((inportb(used_com_addr + MSR) & 0xf0)) return 0;
outportb(used_com_addr + MCR, 0x1f);
if ((inportb(used_com_addr + MSR) & 0xf0) != 0xf0) return 0;
outportb(used_com_addr + MCR, old_data);
// write values to scratch pad and readback
old_data = inportb(used_com_addr + SPR);
outportb(used_com_addr + SPR, 0x55);
if (inportb(used_com_addr + SPR) != 0x55) return 1;
outportb(used_com_addr + SPR, 0xAA);
if (inportb(used_com_addr + SPR) != 0xAA) return 1;
outportb(used_com_addr + SPR, old_data);
// enable fifo and determine version by part identification
outportb(used_com_addr + FCR, 1);
old_data = inportb(used_com_addr + FCR);
outportb(used_com_addr + FCR, 0);
if ((~old_data & 0x80)) return 2; // 16450
if ((~old_data & 0x40)) return 3; // 16550
return 4; // 16550a +
}
// inits the serial com port with a specific baud rate,
// using interrupt or polling method.
void init_com_port(int com_no, long baudrate, int intr = 0)
{
// calculate divisor relative to the baudrate
short divisor = (long)115200 / baudrate;
used_com_addr = get_com_addr(com_no);
if (used_com_addr == 0) {
printf("no valid com port!\n");
return ;
}
printf("serial com port addr 0x%x", used_com_addr);
if (intr)
printf(" [irq %d, ", used_com_irq);
else printf("[");
int uart_type = detect_uart_type();
switch(uart_type) {
//case 0: break; // port must be found already by bios.
case 1: printf("8250"); break;
case 2: printf("16450"); break;
case 3: printf("16550"); break;
case 4: printf("16550a"); break;
}
printf("] is initialized!\n");
intr_used = intr;
disable();
// turn off interrupts
outportb(used_com_addr + 1, 0);
// set dlab bit, so we can update the divisor
outportb(used_com_addr + LCR, 0x80);
// set divisor lsb
outportb(used_com_addr + DIVLSB, divisor & 0xff);
// set msb
outportb(used_com_addr + DIVMSB, (divisor >> 8) & 0xff);
// frame: 8 data bits, no parity and 1 stop bit
outportb(used_com_addr + LCR, 0x3);
// set RTS | DTR | OUT2(if intr) to inform remote system that we are ready
outportb(used_com_addr + MCR, 0x3 | ((intr == 1) << 3));
// support interrupt?
if (intr) {
// save old serial port interrupt handler address
old_handler = getvect(8 + used_com_irq);
setvect(8 + used_com_irq, new_handler);
// enable serial port irq at pic
outportb(0x21, inportb(0x21) & ~(1 << used_com_irq));
// let the interrupt be triggered upon data arrival
outportb(used_com_addr + IER, 1);
} else {
// no interrupt should be triggered
outportb(used_com_addr + IER, 0);
}
// does the uart support fifo?
if (uart_type == 4) {
// set fifo buffer of 14 bytes, clear receive and transmit fifo's
outportb(used_com_addr + FCR, 0xc7);
}
// clear delta bits
inportb(used_com_addr + LSR);
// clear incoming byte
inportb(used_com_addr + RBR);
enable();
}
// the serial port interrupt handler
// called upon received data only
// saves data in a stack
void interrupt new_handler(...)
{
unsigned char status = 0;
disable();
// read iir and msr to acknowledge the uart
inportb(used_com_addr + IIR);
inportb(used_com_addr + MSR);
// as long as data is arriving, put it in the stack
do {
// read status register
status = inportb(used_com_addr + LSR) & 0x1;
if (status & 1) {
// read data from com port to the stack
*next_char++ = inportb(used_com_addr + RBR);
// overlap offset in case the stack is full
next_char = ((next_char - recv_stack) % STACK_SIZE) + recv_stack;
}
}while (status & 1);
enable();
// let the pic know we are done
outportb(0xa0, 0x20);
outportb(0x20, 0x20);
}
// send a byte to the initialized com port
void send_byte(unsigned char ch)
{
// make sure the connection is alive
if (inportb(used_com_addr + MSR) & 0x80 == 0) return;
// make sure the transmit hold register is empty
while (inportb(used_com_addr + LSR) & 0x20 == 0) ;
// send the character
outportb(used_com_addr + THR, ch);
}
// receive a byte from the initialized com port
unsigned char recv_byte(int* is_read)
{
int i;
*is_read = 0;
if (intr_used)
if (next_char > recv_stack)
{
*is_read = 1;
return *--next_char;
} else return 0;
// is data set ready high?
for (i = 5; i > 0; i--)
if (inportb(used_com_addr + MSR) & 0x20) break;
if (!i) return -1;
// is there anything to read?
for (i = 5; i > 0; i--)
if (inportb(used_com_addr + LSR) & 0x1) break;
if (!i) return -2;
*is_read = 1;
return inportb(used_com_addr + RBR);
}
// enter loop-mode for debugging and testing.
void enter_loop_mode()
{
outportb(used_com_addr + MCR, inportb(used_com_addr + MCR) | 0x10);
}
// exit a loop mode, change to transimtter/receiver mode
void exit_loop_mode()
{
outportb(used_com_addr + MCR, inportb(used_com_addr + MCR) & ~0x10);
}
// shut down serial port connection
void shutdown_com_port()
{
disable();
if (intr_used) {
// set the old handler
setvect(8 + used_com_irq, old_handler);
// disable used serial port interrupt at pic
outportb(0x21, inportb(0x21) | (1 << used_com_irq));
}
// disable serial port interrupt
outportb(used_com_addr + IER, 0);
// disable interrupt, RTS and DTR
outportb(used_com_addr + MCR, 0);
outportb(used_com_addr + FCR, 0);
enable();
}
int main()
{
clrscr();
init_com_port(1, 9600, 1);
for(;;) {
if (kbhit()) {
int c = getch();
if (c == 27) break;
printf("%c", c);
send_byte(c);
}
int b = 0;
unsigned char c = recv_byte(&b);
if (b) printf("%c", c);
}
shutdown_com_port();
return 1;
}