I need to read values form a distance sensor in volts. The sensor sends the voltages binary values to the MUC (Atmega8) and then the atmega8 communicates to my pc using USART with and RS232 cable. The readings displayed on the PC are weird random characters. I don't understand what am I doing wrong.
Here is my code
//USART communicating with Atmega8
#include <avr/io.h>
#include <inttypes.h>
#include <util/delay.h>
#include <string.h>
//1MHZ Baud 9600
#define F_CPU 1000000
char *Bestbelieve ="t \r\n";
void InitADC()
{
ADMUX=(0<<REFS1)|(1<<REFS1); // For Aref=internal;
ADCSRA=(1<<ADEN)|(0<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //Prescalar div factor =8
}
uint16_t ReadADC()
{
ADMUX=0x05;
//Start Single conversion
ADCSRA|=(1<<ADSC);
//Wait for conversion to complete
while(!(ADCSRA & (1<<ADIF)));
//Clear ADIF by writing one to it
//Note you may be wondering why we have write one to clear it
//This is standard way of clearing bits in io as said in datasheets.
//The code writes '1' but it result in setting bit to '0' !!!
ADCSRA|=(1<<ADIF);
return(ADC);
}
void Wait()
{
uint8_t i;
for(i=0;i<20;i++)
_delay_loop_2(0);
}
char USARTReadChar()
{
//Wait until a data is available
while(!(UCSRA & (1<<RXC)))
{
//Do nothing
}
//Now USART has got data from host
//and is available is buffer
return UDR;
}
void USARTWriteChar(char* data)
{
//Wait until the transmitter is ready
while(*data)
{ while(!(UCSRA & (1<<UDRE)))
{
//Do nothing
}
//Now write the data to USART buffer
UDR=*data;
data++;
}}
void USARTInit(uint16_t ubrr_value)
{
UBRRL = 12;
UBRRH = 0;
UCSRC=(1<<URSEL)|(3<<UCSZ0);
UCSRB=(1<<RXEN)|(1<<TXEN);
UCSRA=(1<<U2X);
}
int main()
{
uint16_t adc_result;
//Initialize ADC
InitADC();
USARTInit(12); //UBRR = 12
//Loop forever
while(1)
{
adc_result=ReadADC(); // Read Analog value from channel-0
char *result[15];
sprintf(result,"%d",adc_result);
Wait();
USARTWriteChar(adc_result);
/* The code continuously has t outputted and skipped lines.
*/
}
}
You are using sprintf to format your data into result. However, you then use USARTWriteChar on your binary value adc_result.
You need to print out result instead, presumably with a loop over the characters calling USARTWriteChar.
Related
So I am having a tough time setting up my SPI, and getting it to work with the LSM330 device to read accelerometer data. I'm simply setting up the SPI system, and trying to use that to read the WHO_AM_I_A register to confirm that it is working and all I'm getting back is 0xff rather than 0x40.
Here is my code:
main.c
#include <avr/io.h>
#include "LSM330.h"
#include "spi.h"
#include "CLK.h"
#include "accel.h"
int main(void) {
//set clock
set32MhzClock();
//first set SPI slave selects for accel gyro to false(high)
PORTF.OUTSET = PIN4_bm | PIN3_bm;
//set serial system of SPI
PORTA_OUTCLR = PIN4_bm;
//init SPI
spi_init();
//reset LSM330 accel by sending 0x01 to CTRL_REG4_A
accel_write(0x01, CTRL_REG4_A);
//trying to read from WHO_AM_I_A reg
uint8_t whoAreYou = accel_read(WHO_AM_I_A);
printf(whoAreYou);
}
accel.h
#include "LSM330.h"
#include "spi.h"
void accel_write(uint8_t reg_addr, uint8_t data) {
//make slave select signal LOW
PORTF_OUTCLR = PIN3_bm;
//set sensor_sel
PORTF_OUTSET = PIN2_bm;
//first write reg_addr, w/ RW=0 and MS=0
uint8_t writeResult = spi_write(reg_addr);
//then write data byte
spi_write(data);
return;
}
spi.h
void spi_init(void) {
//set correct pins as outputs and inputs
PORTF.DIRSET = PIN7_bm | PIN5_bm | PIN4_bm | PIN3_bm; //SCK, MOSI, SSG, SSA as outputs
PORTF.DIRCLR = PIN6_bm; //MISO as input
//set up SPI as master
SPIF.CTRL = SPI_ENABLE_bm | SPI_MASTER_bm | SPI_MODE_3_gc | SPI_PRESCALER_DIV16_gc;
//clear spi interrupt flag by reading spsr and spdr
SPIF_STATUS;
SPIF_DATA;
return
}
uint8_t spi_write(uint8_t dataIn) {
//write data
SPIF.DATA = dataIn;
//wait for transmission to complete
while(!(SPIF_STATUS & SPI_IF_bm));
return SPIF.DATA;
}
uint8_t spi_read(vodi) {
return spi_write(0xFF);
}
And that's all I have. Have tried many things, and can't seem to get this thing to work. It seems like SPI is working because it's not getting stuck up in any of the while loops when writing data.
Without going too much into the details, there is definitely something wrong here:
//reset LSM330 accel by sending 0x01 to CTRL_REG4_A
accel_write(0x01, CTRL_REG4_A);
But the declaration of your function is as follows:
void accel_write(uint8_t reg_addr, uint8_t data)
It seems you are setting register 0x01 to value of CTRL_REG4_A.
I'm trying to develop a interface SPI and I have started with a simple configuration.
The question is that SCK seems to work fine but MOSI doesnt works.
Here is my code and my test logical tester.
#include <stdlib.h>
#include <plib.h>
// example functions prototypes
int SpiDoMasterSlaveExample(int nCycles);
void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster);
// some definitions
#define MIN_SPI_TXFER_SIZE 8 // min number of words per transfer
#define MAX_SPI_TXFER_SIZE 512 // max number of words per transfer
// configuration settings
#pragma config FNOSC = PRIPLL, POSCMOD = HS, FPLLMUL = MUL_18, FPLLIDIV = DIV_2, FPBDIV = DIV_2, FPLLODIV = DIV_1
#pragma config FWDTEN = OFF
int main(void)
{
SYSTEMConfigPerformance(72000000L);
srand(ReadCoreTimer()); // seed the pseudo random generator
if(!SpiDoMasterSlaveExample(100))
{
return 0; // our example failed
}
return 1;
}
int SpiDoMasterSlaveExample(int nCycles)
{
int fail=0; // overall result
SpiInitDevice(1, 1, 1, 1); // initialize the SPI channel 1 as master, frame master
SpiInitDevice(2, 0, 1, 0); // initialize the SPI channel 2 as slave, frame slave
while(nCycles-- && !fail)
{
unsigned int txferSize;
unsigned short* pTxBuff;
unsigned short* pRxBuff;
txferSize=MIN_SPI_TXFER_SIZE+rand()%(MAX_SPI_TXFER_SIZE-MIN_SPI_TXFER_SIZE+1); // get a random transfer size
pTxBuff=(unsigned short*)malloc(txferSize*sizeof(short));
pRxBuff=(unsigned short*)malloc(txferSize*sizeof(short)); // we'll transfer 16 bits words
if(pTxBuff && pRxBuff)
{
unsigned short* pSrc=pTxBuff;
unsigned short* pDst=pRxBuff;
int ix;
int rdData;
for(ix=0; ix<txferSize; ix++)
{
pTxBuff[ix]='A'; // fill buffer with some random data
}
ix=txferSize+1; // transfer one extra word to give the slave the possibility to reply back the last sent word
while(ix--)
{
SpiChnPutC(1, *pSrc++); // send data on the master channel, SPI1
rdData=SpiChnGetC(1); // get the received data
if(ix!=txferSize)
{ // skip the first received character, it's garbage
*pDst++=rdData; // store the received data
}
rdData=SpiChnGetC(2); // receive data on the slave channel, SPI2
SpiChnPutC(2, rdData); // relay back data
}
// now let's check that the data was received ok
pSrc=pTxBuff;
pDst=pRxBuff;
for(ix=0; ix<txferSize; ix++)
{
if(*pDst++!=*pSrc++)
{
fail=1; // data mismatch
break;
}
}
}
else
{ // memory allocation failed
fail=1;
}
free(pRxBuff);
free(pTxBuff); // free the allocated buffers
}
return !fail;
}
void SpiInitDevice(int chn, int isMaster, int frmEn, int frmMaster)
{
unsigned int config=SPI_CON_MODE16|SPI_CON_SMP|SPI_CON_ON; // SPI configuration word
if(isMaster)
{
config|=SPI_CON_MSTEN;
}
if(frmEn)
{
config|=SPI_CON_FRMEN;
if(!frmMaster)
{
config|=SPI_CON_FRMSYNC;
}
}
SpiChnOpen(chn, config, 4); // divide fpb by 4, configure the I/O ports. Not using SS in this example
}
Sorry, I can't post the logical analyser image for my reputation points.
I'm trying to send "A" all time (fill buffer transmit). That's send data to SPI1.
I'm reading SPI1 from my Microchip Expansion Board I/O where SPI1 is in pins 41 and 43 (41 SCK and 43 SDO).
In SPI2, pin 23 and 25, obviously I have not any traffic.
Does anyone have idea of this error?
Thanks a lot
The PIC32MX series has mapable input and output pins for some peripherals, including the SPI. This means, that MOSI and MISO can be mapped to different pins, depending on your specific needs.
You need to specify this in code before you start using the SPI, otherwise, the PIC won't know which pins to use.
The following is just an example of how to setup the pins (peripheral pin select). You need to look in your PIC's datasheet for the mappings. The first parameter in the calls is the table index from the datasheet.
/* inputs */
PPSInput(2, SDI1, RPF2); // F2, MEMORY MISO -> SPI1SDI
PPSInput(2, SDI2, RPG7); // G7, ZB MISO -> SPI2SDI
/* outputs */
PPSOutput(4, RPF3, SDO1); // F3, MEMORY MOSI -> SPI1SDO
PPSOutput(1, RPG8, SDO2); // G8, ZB MOSI -> SPI2SDO
As described before, check your peripheral pin select. Additional you must set your port direction to Output (PDx-Register). MISO must be set to an Input.
I'm currently trying to interface my Tiva C Series with a Sparkfun Breakout Board, IMU Digital Combo Board - 6 Degrees of Freedom ITG3200/ADXL345 and I'm having trouble with the I2C interface.
currently this is my code:
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/i2c.h"
uint8_t SLAVE_ADDRESS = 0x68;
uint32_t first_byte, second_byte, temperature, result;
void i2c_setup(void) {
//Enable the I2C Module
SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C2);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
//Wait at least 5 clock cycles
SysCtlDelay(2);
//Configure SDA and SCL
GPIOPinConfigure(GPIO_PE4_I2C2SCL);
GPIOPinConfigure(GPIO_PE5_I2C2SDA);
//Wait at least 5 clock cycles
SysCtlDelay(2);
//Set PE4 as SCL
GPIOPinTypeI2CSCL(GPIO_PORTE_BASE, GPIO_PIN_4);
//Set PE5 as SDA
GPIOPinTypeI2C(GPIO_PORTE_BASE, GPIO_PIN_5);
//Configure Master,
I2CMasterInitExpClk(I2C2_BASE, SysCtlClockGet(), false);
}
uint32_t i2c_read() {
I2CMasterSlaveAddrSet(I2C2_BASE, SLAVE_ADDRESS, false);
I2CMasterDataPut(I2C2_BASE, 0x1A);
I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_SINGLE_SEND);
while(I2CMasterBusBusy(I2C2_BASE)); //Loop until the bus is no longer busy
I2CMasterSlaveAddrSet(I2C2_BASE, SLAVE_ADDRESS, true );
I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);
while(I2CMasterBusBusy(I2C2_BASE)); //Loop until the bus is no longer busy
first_byte = I2CMasterDataGet(I2C2_BASE);
return first_byte;
}
void setup()
{
Serial.begin(9600);
i2c_setup();
}
void loop()
{
int test = i2c_read();
Serial.println(test);
delay(1000);
}
I'm using Energia to test my program, and when I try to read from the specified register, I get the same result, no matter which register I choose, the result is always decimal 229 (this is the Accelerometer's Device Address).
Can somebody point me in the right direction, I've been looking at my code for quite some time and still don't know whats wrong...
Thanks!
I skimmed through your code and everything seems Okay. Clearly something is working right if you get a response. But Like Martin said , figuring the problem without being there is somewhat difficult. Instead of Writing 0x1A can you try using one of the other I2C commands for the accelerametor ? Also if the jumper is connected to VDD your address should be 0x69 (105 decimal) are you sure it's 0x68 ?
I looked up the documentation on sparkfuns website and they provided the following list
of commands.
char WHO_AM_I = 0x00;
char SMPLRT_DIV= 0x15;
char DLPF_FS = 0x16;
char GYRO_XOUT_H = 0x1D;
char GYRO_XOUT_L = 0x1E;
char GYRO_YOUT_H = 0x1F;
char GYRO_YOUT_L = 0x20;
char GYRO_ZOUT_H = 0x21;
char GYRO_ZOUT_L = 0x22;
GL hope everything works out. Been meaning to buy my own to play around with so keep me posted !
I am trying to send a message from my ARM7 LPC2148 board. I have connected a SIM900 GSM Modem to the UART0 of the board. But I am not receiving the message on my phone!!I have put print statements here and there so that I know where the system is and where its stuck. But it prints all the messages. It says message sent even though I have not received any SMS.
Here is the code:
Main code
#include "i2c.h"
#include "LPC214x.H" // LPC2148 MPU Register
#include <stdio.h>
#include "gsm.h"
#include "lcd.h"
#include "buzzer.h"
extern int msgflag;
/* Main Program Start Here */
int main(void)
{
PINSEL0 = 0x00000000; // Enable GPIO on all pins
PINSEL1 = 0x00000000;
PINSEL2 = 0x00000000;
lcd_init(); // Initial LCD
lcd_write_control(0x01); // Clear Display (Clear Display,Set DD RAM Address=0)
goto_cursor(0x00); // Set Cursor Line-1
lcd_print("Accident Alert"); // Display LCD Line-1
// Display LCD Line-2
// Display Delay
// Clear Display (Clear Display,Set DD RAM Address=0)
// Display LCD Line-1
goto_cursor(0x40); // Set Cursor = Line-2
lcd_print("System"); // Display LCD Line-2
delay1(100000000);
gsmperform();
// Loop Print Message to LCD16 x 2 //
// Loop Continue
sendmsg();
msgflag=0;
lcd_write_control(0x01); // Clear Display (Clear Display,Set DD RAM Address=0)
goto_cursor(0x00); // Set Cursor Line-1
lcd_print("Message sent"); // Display LCD Line-1
}
gsm.c
#include<lpc214x.h> /*Header file*/
#include "gsm.h"
#include "lcd.h" //header file
extern unsigned char cmgf[]="AT+CMGF=1"; //Text format in GSM modem
extern unsigned char cmgs[]="AT+CMGS=\"9xxxxxxxxx\""; //Mobile number to which the msg is sent
extern unsigned char msg[]="hello"; //secret code
extern unsigned char readall[]="AT+CMGR=\"REC UNREAD\"\r\n";
extern int blink;
unsigned char content[7];
void txu1(unsigned char data) //Transmit a byte of data through UART1
{
while(!(U1LSR & 0x20)); // Wait until UART1 ready to send character
U1THR = data;
}
unsigned char rxu1()
{
unsigned char p;
while ((U1LSR&0x01)!=1);
p=U1RBR;
return p;
}
unsigned char rxu0()
{
unsigned char p;
while ((U0LSR&0x01)!=1);
p=U0RBR;
return p;
}
void sendstring(unsigned char *p) //Sends a string of data through UART1
{
while(1)
{
if(*p=='\0') break;
txu1(*p++);
}
}
void delaygsm() //delay function
{
int i,j;
for(i=0;i<60000;i++)
for(j=0;j<51;j++);
}
void delay2() //delay function
{
int i,j;
for(i=0;i<60000;i++)
for(j=0;j<200;j++);
}
unsigned char recuart1() //recieves a byte from UART1
{
unsigned char p;
while ((U1LSR&0x01)!=1);
p=U1RBR;
return p;
}
void uart1_irq() __irq //ISR if anything is recieved in UART1, the same is transmitted through UART0
{
unsigned char p;
p=U1RBR;
if(p=='a')
{
sendmsg();
}
VICVectAddr=0;
}
void sendmsg(void)
{
sendstring(msg);
}
void initgsm() //Initialization of UART0,UART1 and ISR
{
U0LCR=0x83;
U0DLL=0x61;
U0DLM=0x00;
U0LCR=0x03;
U1LCR=0x83;
U1DLL=0x61;
U1DLM=0x00;
U1LCR=0x03;
U1IER=0x01;
U1FCR=0x07;
VICIntSelect&=0xffffff7f;
VICVectAddr2=(unsigned int)uart1_irq;
VICIntEnable|=0x00000080;
VICVectCntl2=0x20|7;
}
void gsmperform(void)
{
lcd_write_control(0x01); // Clear Display (Clear Display,Set DD RAM Address=0)
goto_cursor(0x00); // Set Cursor Line-1
lcd_print("begin gsm"); // Display LCD Line-1
PINSEL0|=0x00050005;
PINSEL1|=0x00000000;
PINSEL2|=0x00000000;
initgsm();
sendstring("ATe0\r\n");
delaygsm();
sendstring("AT+CMGD=1,4\r\n");
delaygsm();
sendstring("AT+CNMI=1,0,0,0\r\n");
delaygsm();
lcd_write_control(0x01); // Clear Display (Clear Display,Set DD RAM Address=0)
goto_cursor(0x00); // Set Cursor Line-1
lcd_print("end gsm"); // Display LCD Line-1
}
Break up the problem into three parts - Configuring & sending the command, receiving the correct command, and working together.
Connect your LPC2148 board to a PC, and use a PC terminal program to watch what commands you are sending. Make sure the parts of your program is working correctly. Are you running any optimizing options in your compiler? That will mess up your delay functions for sure. Use a built-in timer to provide the delay, not for loops.
Make sure you are using the correct commands to talk to the GSM card. Connect it to a PC if possible (make sure you convert from logic levels to UART levels if it does not have an RS-232 transceiver on it), or to a kit running an interactive terminal. Make sure your commands actually will send an SMS message with the module you have chosen.
Now connect the kit and the module. By now you should know which signals are actually outputs and which are inputs - RS-232 can be very confusing about this. Most processor UARTs are labelled as DTE (TX==output, RX==input), and I'd expect the comms module labeled as DCE (TX==input, RX==output), which means that you would connect RX<->RX and TX<->TX. If they are both labeled as DTE, then you need a null-modem cable to swap the signals, or do it by hand when attaching the board.
I have an atom board with a Fintek F75111 GPIO. I have info from the manufacturer that the SMbus address to access the chip is 06EH.
I am trying to read and write values to the GPIO in Linux. I have a sample program from manufacturer written for Windows that looks like this.
#include “math.h”
#include “stdio.h”
#include “dos.h”
void main(void){
int SMB_PORT_AD = 0x400;
int SMB_DEVICE_ADD = 0x6E;
/*75111R’s Add=6eh */
//programming DIO as output //0:input 1:Output
/* Index 10, GPIO1x Output pin control */
SMB_Byte_WRITE(SMB_PORT_AD,SMB_DEVICE_ADD,0x10,0xff); delay(10);
//programming DIO default LOW
/* Index 11, GPIO1x Output Data value */
SMB_Byte_WRITE(SMB_PORT_AD,SMB_DEVICE_ADD,0x11,0x00); delay(10);
}
unsigned char SMB_Byte_READ (int SMPORT, int DeviceID, int REG_INDEX)
{
unsigned char SMB_R;
outportb(SMPORT+02, 0x00); /* clear */
outportb(SMPORT+00, 0xff); /* clear */
delay(10);
outportb(SMPORT+04, DeviceID+1); /* clear */
outportb(SMPORT+03, REG_INDEX); /* clear */
outportb(SMPORT+02, 0x48); /* read_byte */
delay(10);
SMB_R= inportb(SMPORT+05);
return SMB_R;
}
void SMB_Byte_WRITE(int SMPORT, int DeviceID, int REG_INDEX, int REG_DATA)
{
outportb(SMPORT+02, 0x00); /* clear */
outportb(SMPORT+00, 0xff); /* clear */
delay(10);
outportb(SMPORT+04, DeviceID); /* clear */
outportb(SMPORT+03, REG_INDEX); /* clear */
outportb(SMPORT+05, REG_DATA); /* read_byte */
outportb(SMPORT+02, 0x48); /* read_byte */
delay(10);
}
I have tried to translate this to Linux compatible functions inb() and outb() and this is what I got.
#include <stdio.h>
#include <sys/io.h>
unsigned int gpio_read(int PORT, int DEVICE, int REG_INDEX){
unsigned int RESPONSE;
outb(0x00, PORT+02);
outb(0xff, PORT+00);
usleep(100);
outb(DEVICE+1, PORT+04);
outb(REG_INDEX, PORT+03);
outb(0x48, PORT+02);
usleep(100);
RESPONSE = inb(PORT+05);
return RESPONSE;
}
unsigned int gpio_write(int PORT, int DEVICE, int REG_INDEX, int REG_DATA){
outb(0x00, PORT+02);
outb(0xff, PORT+00);
usleep(100);
outb(DEVICE, PORT+04);
outb(REG_INDEX, PORT+03);
outb(DATA, PORT+05);
outb(0x48, PORT+02);
usleep(100);
}
void main() {
int PORT = 0x400;
int DEVICE = 0x6E;
unsigned int RESPONSE;
// Ask access to port from kernel
ioperm(0x400, 100, 1);
// GPIO1x set to input (0xff is output)
gpio_write(PORT, DEVICE, 0x10, 0x00);
RESPONSE = gpio_read(PORT, DEVICE, 1);
printf("\n %u \n", RESPONSE);
}
GPIO1X index 0x10 is used to set if the 8 GPIO ports that are connected to GPIO1x are output ports or input ports.
Output values for GPIOs are set using the index 0x11, and if the ports work as input ports then index 0x12 is used for reading input values.
The problem is that I do not know if this is correct or how to read the values (why the read function outputs something before reading?!?)
When I run:
RESPONSE = gpio_read(PORT, DEVICE, X);
Changing X with values from 1..9 I get this as output: 0 8 8 0 0 0 0 0 0
The number 8 confuses me...
Instead of writing directly to the SMBus port, I'd rather use the i2c libraries. I2C (and SMBUS) use two Port Pins, one for the clock and one for the data. The data is trasmitted and received at the clock edges (synchronous), Reading the code, I cannot see clearly which of them (clock or data) is being accessed and when.
To get started I'd use i2ctools as a start point (check this site: http://elinux.org/Interfacing_with_I2C_Devices). This tool helps you to find devices connected to the I2C bus to your microprocessor and also perform basic commmunication.
Hope it helps...