#include <linux/module.h>
#include <linux/kernel.h>
//#include <linux/init.h>
#include <linux/types.h>
#include <linux/input.h>
//#include <linux/input-polldev.h>
//#include <linux/delay.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <stdint.h>
/*
MAHIR SHAHRIAR
30027575
CPSC 359
ASSIGNMENT 2
*/
#define GPIO_CLOCKPIN 23 // pin used for clock output GPIO 11 (SPI_SCLK)
#define GPIO_LATCHPIN 21 // pin used for latch output GPIO 9 (SPI_MISO)
#define GPIO_DATAPIN 19 // pin used for data input from controller GPIO 10 (SPI_MOSI)
#define GPIO_POWERPIN 1 // 3.3 VOLT POWER SOURCE Programmble input to set high/low
#define GPIO_GROUNDPIN 9 // Pin used for grounding
#define GPIO_BASEADDRESS 0xfe200000 // Base address used to offset to other registers
//volatile unsigned *gpio = (unsigned*)0xfe200000; // gpio pointer to base address
volatile uint32_t *gpio = (unsigned*)0xfe200000;
volatile uint32_t *GPFSEL1 = (unsigned*)0xfe200000 + 0x04/4; //pointer to register GPFSEL1 for pins 10-19
volatile unsigned *GPFSEL2 = (unsigned*)0xfe200000 + 0x08/4; //pointer to register GPFSEL2 for pins 20-29
volatile unsigned *GPSET0 = (unsigned*)0xfe200000 + 0x1c/4; //pointer to register GPSET0 for setting high
volatile unsigned *GPCLR0 = (unsigned*)0xfe200000 + 0x28/4; //pointer to register GPCLR0 for setting low
volatile unsigned *GPLEV0 = (unsigned*)0xfe200000 + 0x34/4; //pointer to register GPLEV0 for reading data from pin
volatile unsigned *GPIO_PUP_PDN_CNTRL_REG1 = (unsigned*)0xfe200000 + 0xe8/4; //pointer to register for controlling pull up pull down
// INIT GPIO Function takes user inputs for Initializing a particular GPIO Pin number.
// It takes data such as the PIN NUMBBER , string "input" or "output" ,
// string "high" or "low " and string "pullup" or "pulldown"
// Depending on the arguments passed into the Init_GPIO function or subroutine
static void Init_GPIO(int pin_number, char type, char high_low, char pullup_pulldown) {
// setting valueinput valueoutput and mask to set the input output of the pin type
int valueinput = 0b000 << ( (pin_number-10)*3 ); // bits to be set for input
int valueoutput = 0b001 << ( (pin_number-10)*3 ); // bits to be set for output
int mask = 0b111 << ( (pin_number-10)*3 ); // for ensuring other bits dont change
// condition to check which register to access for the bits and setting to input or output based on
// function calls from main and arguments passed
if(pin_number<=19){
if(type == 'i'){
printf("%x", GPFSEL1);
//*GPFSEL1 = (*GPFSEL1 & ~mask) | (valueinput * mask); //problem
}
else if(type == 'o'){
//*GPFSEL1 = (*GPFSEL1 & ~mask) | (valueoutput * mask);
}
else{
//no type specified
printf("Input type not specified please use 'o' or 'i' ignore if not specifying output input type for pin\n");
}
if(pin_number > 19 && pin_number <=29 ){
if(type == 'i'){
//*GPFSEL2 = (*GPFSEL2 & ~mask) | (valueinput * mask);
}
else if(type == 'o'){
//*GPFSEL2 = (*GPFSEL2 & ~mask) | (valueoutput * mask);
}
else{
//no type specified
printf("Input type not specified please use 'o' or 'i' ignore if not specifying output input type for pin\n");
}
}
// Setting the pin to either high or low
if(high_low == 'h'){
//*GPSET0 = 1 << pin_number;
}
else if(high_low == 'l'){
//*GPCLR0 = 1 << pin_number;
}
else{
// high low not specified
printf("high low not specified please use 'h' or 'l' ignore if not specifying highlow for pin\n");
}
}
// Setting if the pin uses pull up or pull down register
int value_pullup = 0b01 << ( (pin_number -16)*2 );
int value_pulldown = 0b10 << ( (pin_number -16)*2 );
mask = 0b11 << ( (pin_number -16)*2 );
if(pullup_pulldown == 'p'){
//*GPIO_PUP_PDN_CNTRL_REG1 = ( *GPIO_PUP_PDN_CNTRL_REG1 & ~mask ) | (value_pullup) & mask;
}
else if(pullup_pulldown == 'n'){
//*GPIO_PUP_PDN_CNTRL_REG1 = ( *GPIO_PUP_PDN_CNTRL_REG1 & ~mask ) | (value_pulldown) & mask;
}
else {
// user does not set any pull up or pull down value for the assigned pin
printf("pull up pull down not specified please use 'p' or 'n' ignore if not specifying pullup pulldown for pin\n");
}
}
void main() {
printf("pointer address %p " , gpio);
Init_GPIO(18, 'i', 'l', 'p');
volatile uint32_t valueinput = 0b000 << ( (18-10)*3 ); // bits to be set for input
volatile uint32_t valueoutput = 0b001 << ( (18-10)*3 ); // bits to be set for output
volatile uint32_t mask = 0b111 << ( (18-10)*3 );
*GPFSEL1 = (*GPFSEL1 & ~mask) | (valueinput * mask);
}
I am getting segmentation error for the last line in main. I dont know why this is doing that. How do I fix the issue I am trying to change the bits in the register GPFSEL1 for the raspberry pi 4 GPIO for changing the input mode by changing bits to 000 for my pin 18 for putting in into input mode. Any help or direction would be greatly appreciated!
I am currently using "STM32F429I-DISC1" with joystick. I am trying to draw something on the LCD screen and using joystick move this object. My drawing is working fine, but I have the error: " void value not ignored as it ought to be".
This two lines have problems...
localX = Joy_ReadXY(CTRL_REG_IN3);
localY = Joy_ReadXY(CTRL_REG_IN4);
Can someone please tell me, how I can fix this error?
And why I see this error?
Main.c
#include "stm32f429i_discovery_lcd.h"
#define CTRL_REG_IN3 0b00011000
#define CTRL_REG_IN4 0b00100000
SemaphoreHandle_t xMutex;
Joystick_data xy;
void vTaskFunction1(void *pvParameters) {
uint16_t localX;
uint16_t localY;
for(;;) {
localX = Joy_ReadXY(CTRL_REG_IN3);
localY = Joy_ReadXY(CTRL_REG_IN4);
xSemaphoreTake( xMutex, portMAX_DELAY );
xy.x = localX;
xy.y = localY;
xSemaphoreGive( xMutex );
HAL_Delay(10);
}
}
void vTaskFunction2(void *pvParameters) {
uint32_t xCoord = 240/2;
uint32_t yCoord = 320/2;
uint8_t reads = 0;
uint8_t ballRadius = 5;
uint16_t xLimitMin = ballRadius+25;
uint16_t xLimitMax = 240-ballRadius-25;
uint16_t yLimitMin = ballRadius+25;
uint16_t yLimitMax = 320-ballRadius-25;
for(;;) {
xSemaphoreTake( xMutex, portMAX_DELAY );
if (xy.x > 3000 && !(xCoord < xLimitMin))
xCoord -= 5;
if (xy.x < 1000 && !(xCoord > xLimitMax))
xCoord += 5;
if (xy.y > 3000 && !(yCoord < yLimitMin))
yCoord -= 5;
if (xy.y < 1000 && !(yCoord > yLimitMax))
yCoord += 5;
reads++;
BSP_LCD_Clear(LCD_COLOR_WHITE);
BSP_LCD_DrawCircle(xCoord, yCoord, ballRadius);
BSP_LCD_FillCircle(xCoord, yCoord, ballRadius);
xSemaphoreGive(xMutex);
HAL_Delay(20);
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI4_Init();
MX_TIM1_Init();
MX_USART1_UART_Init();
// LCD Things
BSP_LCD_Init();
BSP_LCD_LayerDefaultInit(1, LCD_FRAME_BUFFER);
BSP_LCD_SelectLayer(1);
BSP_LCD_SetBackColor(LCD_COLOR_WHITE); // Vali meelepärane värv
BSP_LCD_Clear(LCD_COLOR_WHITE);
BSP_LCD_SetTextColor(LCD_COLOR_DARKBLUE); // Vali meelepärane värv
MX_FREERTOS_Init();
if ( xMutex == NULL )
{
xMutex = xSemaphoreCreateMutex();
if ( ( xMutex ) != NULL )
xSemaphoreGive( ( xMutex ) );
}
xTaskCreate(vTaskFunction1, "Task 1", 100, NULL, 1, NULL);
xTaskCreate(vTaskFunction2, "Task 2", 100, NULL, 1, NULL);
vTaskStartScheduler();
osKernelStart();
while (1)
{
}
}
Read joystick function (joystick.c)
#include <stdio.h>
#include <main.h>
#include "gpio.h"
#include "spi.h"
#define READ_SLAVE_OPERATION 0b10000000
#define READ_INCR_SLAVE_OPERATION 0b11000000
#define WRITE_SLAVE_OPERATION 0b00000000
#define CTRL_REG_IN3 0b00000011
#define CTRL_REG_IN4 0b00000100
#define OUT_X_L 0x28
#define OUT_X_H 0x29
#define OUT_Y_L 0x2A
#define OUT_Y_H 0x2B
#define OUT_Z_L 0x2C
#define OUT_Z_H 0x2D
#define JOY_CS_LOW() HAL_GPIO_WritePin(JOY_CS_GPIO_PORT, JOY_CS_PIN, 0)
#define JOY_CS_HIGH() HAL_GPIO_WritePin(JOY_CS_GPIO_PORT, JOY_CS_PIN, 1)
#define JOY_CS_GPIO_PORT GPIOC
#define JOY_CS_PIN GPIO_PIN_13
int16_t Joy_ReadXY(uint8_t reg1){
uint8_t pTxData1[2] = {reg1, 0};
uint8_t pRxData1[2] = {0, 0};
JOY_CS_LOW();
HAL_SPI_TransmitReceive(&hspi4, pTxData1, pRxData1, 2, HAL_MAX_DELAY);
JOY_CS_HIGH();
return pRxData1[0] << 8 | pRxData1[1];
}
Here, in Main.c, you call the function before telling the compiler about what parameters and what return value types it has.
localX = Joy_ReadXY(CTRL_REG_IN3);
localY = Joy_ReadXY(CTRL_REG_IN4)
That confused the compiler and it starts "guessing" about them.
Guessing that it is a void-returning function, the compiler then complains that you are expecting a return value from a function which does return void i.e. nothing.
The returned void should be ignored, instead of attempting to write it to a variable. At least that is what the compiler thinks...
To fix it, you should explain to the compiler that there is a function elsewhere, with name, parameters and return value type. That is done by providing the prototype
int16_t Joy_ReadXY(uint8_t reg1);
It needs to be done before the function body in which the the extern function is first called. (And you already confirmed in comments that it fixes the described problem in your code.)
Note that for the other shown functions this is not needed, because they are defined (with head and body) before they are called.
Similar for other functions, which have their prototype provided in the header you include early on.
Actually, putting the prototype of your function into a header and including that similarily would be the best way to solve this.
I am not an expert c programmers and in the c code I m getting these kinds of errors. I got many and tried to sort them out but can not solve these. The code is as follows:
/*
* EEPROM.c
* interfacing microchip 24aa64f IC with atmel sam4e
*/
#include <asf.h>
#include "EEPROM_I2C.h"
#define DEVICE_ADDRESS 0x50 // 7-bit device identifier 0101000, (refer datasheet)
//#define EEPROM_NAME 24AA6F
#define I2C_FAST_MODE_SPEED 400000//TWI_BUS_CLOCK 400KHz
#define TWI_CLK_DIVIDER 2
#define TWI_CLK_DIV_MIN 7
#define TWI_CLK_CALC_ARGU 4
#define TWI_CLK_DIV_MAX 0xFF
/*************************** Main function ******************************/
int eeprom_main( void )
{
struct micro24 ptMicro24 ;
typedef struct twi_options twi_options_t;
typedef struct Twi_registers Twi;
char TxBuffer[128] ;
char RxBuffer[128] ;
int BufferIndex;
unsigned int PageCount;
unsigned int error = 0 ;
unsigned int i;
ptMicro24.PageSize = 32;
ptMicro24.NumOfPage = 128;
ptMicro24.EepromSize = 128*32;
ptMicro24.SlaveAddress = DEVICE_ADDRESS;
ptMicro24.EepromName = 64;
/***************************** CLOCK SETTINGS TO GET 400KHz **********************
* Set the I2C bus speed in conjunction with the clock frequency.
* param p_twi Pointer to a TWI instance.
* return value PASS\Fail New speed setting is accepted\rejected
**********************************************************************************/
uint32_t twi_set_speed(struct Twi_registers *Twi, uint32_t ul_speed, uint32_t ul_mck)
//uint32_t twi_set_speed(Twi *p_twi, uint32_t ul_speed, uint32_t ul_mck)
{
uint32_t ckdiv = 0; //clock divider is used to increase both TWCK high and low periods (16-18)
uint32_t c_lh_div; //CHDIV (0-7) and CLDIV (8-15)
if (ul_speed > I2C_FAST_MODE_SPEED) { //ul_speed is the desired I2C bus speed
return FAIL;
}
c_lh_div = ul_mck / (ul_speed * TWI_CLK_DIVIDER) - TWI_CLK_CALC_ARGU; //ul_mck main clock of the device
/* cldiv must fit in 8 bits, ckdiv must fit in 3 bits */
while ((c_lh_div > TWI_CLK_DIV_MAX) && (ckdiv < TWI_CLK_DIV_MIN))
{
ckdiv++; // Increase clock divider
c_lh_div /= TWI_CLK_DIVIDER; //Divide cldiv value
}
/* set clock waveform generator register */
Twi->TWI_CWGR =
TWI_CWGR_CLDIV(c_lh_div) | TWI_CWGR_CHDIV(c_lh_div) |
TWI_CWGR_CKDIV(ckdiv);
return PASS;
}
/************************************ Initialize TWI master mode ************************
* Set the control register TWI_CR by MSEN and SVDIS
* param p_opt Options for initializing the TWI module
* return TWI_SUCCESS if initialization is complete
* twi_options... structure contains clock speed, master clock, chip and smbus
*****************************************************************************************/
uint32_t twi_master_start(struct Twi_registers *Twi, struct twi_options_t *twi_options_t)
//uint32_t twi_master_start(Twi *p_twi, const twi_options_t *p_opt)
{
uint32_t status = TWI_SUCCESS; // status success return code is 0
// Enable master mode and disable slave mode in TWI_CR
Twi -> TWI_CR_START = TWI_CR_START;
Twi->TWI_CR_MSEN = TWI_CR_MSEN; // Set Master Enable bit
Twi->TWI_CR_SVDIS = TWI_CR_SVDIS; // Set Slave Disable bit
/* Select the speed */
//new//if (twi_set_speed(Twi->TWI_SR, twi_options_t->speed, twi_options_t->master_clk) == FAIL)
//if (twi_set_speed(Twi, twi_options_t->speed, twi_options_t->master_clk) == FAIL)
//{
//status = TWI_INVALID_ARGUMENT; /* The desired speed setting is rejected */
//}
if (twi_options_t->smbus == 0)
{
Twi->TWI_CR_QUICK == 0;
status = TWI_INVALID_ARGUMENT;
}
else
if (twi_options_t->smbus == 1)
{
Twi->TWI_CR_QUICK == 1;
status = TWI_SUCCESS;
}
return status;
}
/***************************** WriteByte Function ********************************
This function uses a two bytes internal address (IADR) along with
Internal word address of eeprom.
Return Value: None
***********************************************************************************/
void WriteByte (struct micro24 *ptMicro24, char Data2Write,
unsigned int Address)
//Data2Write is the data to be written n the eeprom
//struct <micro24 *ptMicro24> : Structure of Microchip 24AA Two-wire Eeprom
//unsigned int Address>: Address where to write
{
unsigned int WordAddress;
unsigned int SlaveAddress;
unsigned char p0=0;
TWI_CR_START ==1;
if (ptMicro24->EepromName == 64 )
{
if ( Address > 0xFFFF)
{
p0 = 1;
/* Mask the 17th bit to get the 16th LSB */
WordAddress = Address & 0xFFFF ;
SlaveAddress = ptMicro24->SlaveAddress + (p0<<16) ;
}
else {
SlaveAddress = ptMicro24->SlaveAddress ;
WordAddress = Address ;
}
}
TWI_CR_STOP ==1;
//TWI_WriteSingleIadr(TWI_IADR_IADR,SlaveAddress, WordAddress,
// TWI_MMR_IADRSZ_2_BYTE, &Data2Write); // declared as extern
// to write to internal address, utilizing internal address and master mode register
//}
/******************** Increase Speed Function *****************************
* TWI is accessed without calling TWI functions
/***************************************************************************/
int NumOfBytes, Count;
int status;
uint32_t Buffer;
/* Enable Master Mode of the TWI */
TWI_CR_MSEN == 1;
// Twi.TWI_CR_MSEN ==1;
//TWI_CR->TWI_CR_MSEN = TWI_CR_MSEN ;
/* Set the TWI Master Mode Register */
Twi->TWI_MMR = (SlaveAddress & (~TWI_MMR_MREAD) | (TWI_MMR_IADRSZ_2_BYTE));
/* Set the internal address to access the wanted page */
Twi -> TWI_IADR = WordAddress ;
/* Wait until TXRDY is high to transmit the next data */
status = TWI_SR_TXRDY;
while (!(status & TWI_SR_TXRDY))
status = TWI_SR_TXRDY;
/* Send the buffer to the page */
for (Count=0; Count < NumOfBytes ;Count++ )
{
Twi ->TWI_THR_TXDATA = Buffer++;
/* Wait until TXRDY is high to transmit the next data */
status = TWI_SR_TXRDY;
while (!(status & TWI_SR_TXRDY))
status = TWI_SR_TXRDY;
}
/* Wait for the Transmit complete is set */
status = TWI_SR_TXCOMP;
while (!(status & TWI_SR_TXCOMP))
status = TWI_SR_TXCOMP;
// add some wait function according to datasheet before sending the next data
// e.g: 10ms
// e.g: WaitMiliSecond (10);
}
/****************************** ReadByte Function **************************
This function uses a two bytes internal address (IADR) along with
Internal word address of eeprom.
Return Value: None
****************************************************************************/
char ReadByte (struct micro24 *ptMicro24,
unsigned int Address) //int Address to read
{
unsigned int WordAddress;
unsigned int SlaveAddress;
char Data2Read ;
unsigned char p0=0;
TWI_CR_START == 1;
//p_twi -> TWI_CR_START = TWI_CR_START;
if (ptMicro24->EepromName == 64)
{
if ( Address > 0xFFFF) {
p0 = 1;
// Mask the 17th bit to get the 16th LSB
WordAddress = Address & 0xFFFF ;
SlaveAddress = ptMicro24->SlaveAddress + (p0<<16) ;
}
else {
SlaveAddress = ptMicro24->SlaveAddress ;
WordAddress = Address ;
}
}
//TWI_ReadSingleIadr(TWI_IADR_IADR,SlaveAddress,WordAddress,
// TWI_MMR_IADRSZ_2_BYTE,&Data2Read);
// declared as extern
// to write to internal address, utilizing internal address and master mode register
return (Data2Read);
}
}
errors are:
(24,19): error: storage size of 'ptMicro24' isn't known
67,5): error: dereferencing pointer to incomplete type
Twi->TWI_CWGR =
error: expected identifier before '(' token
#define TWI_CR_START (0x1u << 0) /**< \brief (TWI_CR) Send a START Condition */
error: expected identifier before '(' token
#define TWI_CR_MSEN (0x1u << 2) /**< \brief (TWI_CR) TWI Master Mode Enabled */
error: expected identifier before '(' token
#define TWI_CR_SVDIS (0x1u << 5) /**< \brief (TWI_CR) TWI Slave Mode Disabled */
error: dereferencing pointer to incomplete type
if (twi_options_t->smbus == 0)
It seems missing the declaration of struct micro24, this may be the cause of first error: error: storage size of 'ptMicro24' isn't known.
The same for declaration of Twi_registers, that is causing other errors.
Either you forgot to declare these structs or to include an header file declaring them.
This question already has answers here:
Why am I only receiving the first address byte? (I2C Protocol)
(4 answers)
Closed 6 years ago.
I'm trying to read some values being returned by a sensor device. It is all hooked up fine, but I'm struggling to retrieve data from the sensor, properly.
In the datasheet it says that I should receive bytes in the order: prediction, status, resistance, tvoc.
My terminal keeps spitting out the same value, 23130 (0x5a5a)
This leads me to believe that I'm not properly calling my i2c_start(). In the protocol readme it says to read with I2C_start(SLAVE_READ_ADDRESS);' I tried replacing the address with the so-called read starting point being 0xB5, but that returns my error.
/* Name: main.c
* Author: <insert your name here>
* Copyright: <insert your copyright message here>
* License: <insert your license reference here>
*/
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <uart.h>
#include <i2c_master.h>
#define LED PB5
#define I2C_READ 0x5A
char buffer[10];
uint16_t val = 0;
uint16_t pred = 0;
uint8_t status = 0;
uint8_t resistance = 0;
uint8_t tvoc = 0;
void getVal()
{
if(i2c_start(I2C_READ))
{
//uart_puts("Start ");
val = ((uint8_t)i2c_read_ack())<<8;
val |= i2c_read_ack();
pred = ((uint16_t)i2c_read_ack())<<8;
pred |= i2c_read_ack();
// status = ((uint8_t)i2c_read_ack())<<8;
// status |= i2c_read_ack();
// resistance = ((uint8_t)i2c_read_ack())<<8;
// resistance |= i2c_read_ack();
// tvoc = ((uint8_t)i2c_read_ack())<<8;
// tvoc |= i2c_read_nack();
i2c_stop();
} else
{
uart_puts("Error");
i2c_stop();
}
}
int main(void)
{
init_uart(57600);
i2c_init();
DDRB = _BV(5);
for(;;)
{
getVal();
itoa(val, buffer, 10); //convert decimal to string base 10
uart_puts(buffer);
uart_puts(" ");
itoa(pred, buffer, 10); //convert decimal to string base 10
uart_puts(buffer);
uart_puts(" ");
itoa(status, buffer, 10); //convert decimal to string base 10
uart_puts(buffer);
uart_puts(" ");
itoa(resistance, buffer, 10); //convert decimal to string base 10
uart_puts(buffer);
uart_puts(" ");
itoa(tvoc, buffer, 10); //convert decimal to string base 10
uart_puts(buffer);
uart_puts(" ");
PORTB = 0xFF;
_delay_ms(500);
PORTB = 0x00;
_delay_ms(500);
}
return 0; /* never reached */
}
The datasheet is very unclear and contains a fault as far as addressing is concerned. The address for WRITING is 0xB4 and the address for READING is 0xB5.
The datasheet says the address is:
BIT 7 6 5 4 3 2 1 0
DATA 1 0 1 1 0 1 0 R/W
which corresponds to 0xB4 or 0xB5 depending on the R/W bit beeing set or not. The error they make in the text is that (0)1011010 is 0x5A but the R/W bit is the least significant bit, not the most significant bit.
The i2c_start function in the i2cmaster library returns 1 to indicate an error, not zero
uint8_t i2c_start(uint8_t address)
{
// ... snip ...
// check if the device has acknowledged the READ / WRITE mode
uint8_t twst = TW_STATUS & 0xF8;
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
return 0;
}
So in your getVal function, you should have
void getVal()
{
if(i2c_start(I2C_READ) == 0) // 0 indicates success
{
In addition, I can't see why you're reading two 16-bit values val and pred from the sensor. The datasheet indicates that pred is the first value returned. You should also read the 8-bit status value to check if the data read is valid.
If I had some enums like
typedef enum {
AN_TRISTATE_0,
AN_TRISTATE_1,
AN_NOTHING,
AN_MOTOR_1,
AN_MOTOR_2,
AN_MOTOR_3,
AN_SENSOR_1,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_func_t;
and
adc_pin_func_t a_particular_pin = ...
, would it be possible it check if the pin is part of a particular group, e.g pin is part of AN_MOTOR or part of AN_SENSOR, instead of having to check against each item in each possible group.
Or are there more efficient ways of doing this, other than using enums?
Thanks in advance
You could create masks for each of the groups:
typedef enum {
AN_TRISTATE_0 = 0x00001,
AN_TRISTATE_1 = 0x00002,
AN_TRISTATE_MASK = 0x0000f,
AN_NOTHING = 0x00010, // Should this be 0x00000 ?
AN_MOTOR_1 = 0x00100,
AN_MOTOR_2 = 0x00200,
AN_MOTOR_3 = 0x00400,
AN_MOTOR_MASK = 0x00f00,
AN_SENSOR_1 = 0x01000,
AN_SENSOR_2 = 0x02000,
AN_SENSOR_3 = 0x04000,
AN_SENSOR_4 = 0x08000,
AN_SENSOR_5 = 0x10000,
AN_SENSOR_MASK = 0xff000
} adc_pin_func_t;
And then simply test a group against the mask using the & operator:
if (a_particular_pin & AN_SENSOR_MASK)
{
// it's a sensor pin
}
else if (a_particular_pin & AN_MOTOR_MASK)
{
// it's a motor pin
}
EDIT: As others have suggested using a range, then you could probably create a macro for the test, which would allow you to change how the test is performed without the need to change the code (always a good thing):
#define IS_AN_SENSOR(x) (((x) & AN_SENSOR_MASK) != 0)
#define IS_AN_MOTOR(x) (((x) & AN_MOTOR_MASK) != 0)
// etc.
and then the test becomes:
if (IS_AN_SENSOR(a_particular_pin))
{
// it's a sensor pin
}
else if (IS_AN_MOTOR(a_particular_pin))
{
// it's a motor pin
}
// etc
If you then needed to change to using a range then only the macros need to change (and you'd obviously need to define the range min/max):
#define IS_AN_SENSOR(x) ((x) >= AN_SENSOR_START && (x) <= AN_SENSOR_END)
// etc
You are free to choose your enum values, so you could do something like this
typedef enum {
AN_TRISTATE_0 = 0x0001,
AN_TRISTATE_1 = 0x0002,
AN_NOTHING = 0x0000,
AN_MOTOR_1 = 0x0010,
AN_MOTOR_2 = 0x0020,
AN_MOTOR_3 = 0x0030,
AN_SENSOR_1 = 0x0100,
AN_SENSOR_2 = 0x0200,
AN_SENSOR_3, /*and so on*/
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_func_t;
Then you can compare bits to check categories. For example, a motor type is the only category that will have non-zero (AN_MOTOR_2 & 0x00F0)
You can do a
typedef enum {
AN_TRISTATE_START,
AN_TRISTATE_0 = AN_TRISTATE_START,
AN_TRISTATE_1,
AN_TRISTATE_END = AN_TRISTATE_1,
AN_NOTHING,
AN_MOTOR_START,
AN_MOTOR_1 = AN_MOTOR_START,
AN_MOTOR_2,
AN_MOTOR_3,
AN_MOTOR_END = AN_MOTOR_3,
AN_SENSOR_START,
AN_SENSOR_1 = AN_SENSOR_START,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5,
AN_SENSOR_END = AN_SENSOR_5
} adc_pin_func_t;
bool inline
is_sensor(int pin)
{
return AN_SENSOR_START <= pin
&& pin <= AN_SENSOR_END
}
and then in your code
if ( is_sensor(pin) )
{
/* body */
}
This way you don't have to care about masking particular values. May be useful if groups contain a lot of values.
You can give values to the enum in exponents of 2. Then you can simply use bitwise AND and OR masks. So you can assign values like 1,2,4,8,16,32... so on.
typedef enum {
AN_TRISTATE_0 = 1,
AN_TRISTATE_1 = 2,
AN_NOTHING = 4,
AN_MOTOR_1 = 8,
AN_MOTOR_2 = 16,
AN_MOTOR_3 = 32,
AN_SENSOR_1 = 64,
AN_SENSOR_2 = 128,
AN_SENSOR_3 = 256,
AN_SENSOR_4 = 512,
AN_SENSOR_5 = 1024
} adc_pin_func_t;
Then for checking with motor type, you can AND with (32+16+8) = 56. So pin & 56, if non zero will mean it is of motor type.
If you really like to have some modularity in your enum (the "hard coded" enum values are also a valid method), you can implement a struct with some OOP flavour. The design become more complicated, but the usage is still simple :
#include <stdio.h>
#include <string.h>
// Every enum will have its first value start at the value of the previous enum's last member PLUS ONE
#define OFFSET_ENUM_MOTOR ( sizeof(adc_pin_tristate_t) )
#define OFFSET_ENUM_SENSOR ( OFFSET_ENUM_MOTOR + sizeof(adc_pin_motor_t) )
///////////////////////////////////////////////////////////////////////////////
// Enum
typedef enum {
AN_TRISTATE_0,
AN_TRISTATE_1,
AN_NOTHING
} adc_pin_tristate_t;
typedef enum {
AN_MOTOR_1 = OFFSET_ENUM_MOTOR,
AN_MOTOR_2,
AN_MOTOR_3
} adc_pin_motor_t;
typedef enum {
AN_SENSOR_1 = OFFSET_ENUM_SENSOR,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_sensor_t;
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Struct for abstraction
typedef struct adc_pin_func2_t{
// our "enum value"
unsigned int enum_id;
// return is the enum is a motor one
int(*isMotor)(struct adc_pin_func2_t*);
} adc_pin_func2_t;
// Struct
///////////////////////////////////////////////////////////////////////////////
// Member methods : return if the enum is a motor one
int
PinFunc_isMotor(
adc_pin_func2_t *This /* object */
)
{
return ( (This->enum_id>=OFFSET_ENUM_MOTOR) && (This->enum_id<OFFSET_ENUM_SENSOR) );
}
// Creation of the structure
// Initialization
static void
PinFunc_Init(
adc_pin_func2_t *This, /* output */
unsigned int identifier /* old enum identifier */
)
{
// copy members
This->enum_id = identifier;
//copy methods (do not forget to do it !)
This->isMotor = PinFunc_isMotor;
}
// Constructor
adc_pin_func2_t
PinFunc_Create(
unsigned int identifier /* old enum identifier */
)
{
adc_pin_func2_t This;
PinFunc_Init(&This, identifier);
return This;
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
main()
{
adc_pin_func2_t pin = PinFunc_Create(AN_NOTHING);
printf("%d \n", pin );
printf("%d \n", pin.isMotor(&pin) );
adc_pin_func2_t pin2 = PinFunc_Create(AN_MOTOR_2);
printf("%d \n", pin2 );
printf("%d \n", pin2.isMotor(&pin2) );
}
The usage of members functions like pin.isMotor(&pin) isn't very elegant (we repeat pin), but it is a shortcoming of C, which is not an OOP language.
If you don't want to have to manually maintain non-overlapping values, then you can very nearly get it all handled for you automatically. The only thing you'll have to figure out is the maximum number of bits in a group:
#define PIN_GROUP_SHIFT 4
#define GET_PIN_GROUP(x) (adc_pin_group_t)((y) >> PIN_GROUP_SHIFT)
#define PIN_GROUP_START(x) XX_GROUP_##x = ((GROUP_##x << PIN_GROUP_SHIFT) - 1),
enum {
GROUP_TRISTATE,
GROUP_NOTHING,
GROUP_MOTOR,
GROUP_SENSOR
} adc_pin_group_t;
typedef enum {
PIN_GROUP_START(TRISTATE)
AN_TRISTATE_0,
AN_TRISTATE_1,
PIN_GROUP_START(NOTHING)
AN_NOTHING,
PIN_GROUP_START(MOTOR)
AN_MOTOR_1,
AN_MOTOR_2,
AN_MOTOR_3,
PIN_GROUP_START(SENSOR)
AN_SENSOR_1,
AN_SENSOR_2,
AN_SENSOR_3,
AN_SENSOR_4,
AN_SENSOR_5
} adc_pin_func_t;
To determine the type of an entry in the enum, use GET_PIN_GROUP(x), and compare it to whichever value of the adc_pin_group_t enum. You can even switch on the result, if that's helpful.
However, that AN_NOTHING entry makes me wonder if your enum is meant to line up with specific values for each entry. are specific values associated with the pins, which you may not be able to assign arbitrarily. In that case you might need to try something complicated (which I haven't tested):
#define GET_PIN_VALUE(x) ((x) & ((1 << PIN_GROUP_SHIFT) - 1)
#define PIN_GROUP_START(x) \
WW_GROUP_##x, \
XX_GROUP_##x = (GROUP_##x << PIN_GROUP_SHIFT) \
+ GET_PIN_INDEX(WW_GROUP_##x) - 1,
Where you need to know the value that your original enum would have used, use GET_PIN_INDEX(x).